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;
248 NEWTEXTMETRICEXW ntm;
252 typedef struct tagFace {
257 DWORD font_data_size;
262 FONTSIGNATURE fs_links;
263 DWORD ntmFlags; /* Only some bits stored here. Others are computed on the fly */
264 FT_Fixed font_version;
266 Bitmap_Size size; /* set if face is a bitmap */
267 BOOL external; /* TRUE if we should manually add this font to the registry */
268 struct tagFamily *family;
269 /* Cached data for Enum */
270 struct enum_data *cached_enum_data;
273 typedef struct tagFamily {
275 const WCHAR *FamilyName;
281 INT adv; /* These three hold to widths of the unrotated chars */
299 typedef struct tagHFONTLIST {
313 struct font_mapping *mapping;
324 struct list hfontlist;
327 float scale_x, scale_y;
330 OUTLINETEXTMETRICW *potm;
332 DWORD total_kern_pairs;
333 KERNINGPAIR *kern_pairs;
336 struct list child_fonts;
341 const WCHAR *font_name;
345 #define GM_BLOCK_SIZE 128
346 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
348 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
349 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
350 #define UNUSED_CACHE_SIZE 10
351 static struct list child_font_list = LIST_INIT(child_font_list);
352 static struct list system_links = LIST_INIT(system_links);
354 static struct list font_subst_list = LIST_INIT(font_subst_list);
356 static struct list font_list = LIST_INIT(font_list);
358 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
359 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
360 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
362 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
364 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
365 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
366 'W','i','n','d','o','w','s','\\',
367 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
368 'F','o','n','t','s','\0'};
370 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
371 'W','i','n','d','o','w','s',' ','N','T','\\',
372 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
373 'F','o','n','t','s','\0'};
375 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
376 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
377 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
378 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
380 static const WCHAR * const SystemFontValues[4] = {
387 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
388 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
390 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
391 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
392 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
393 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
394 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
395 'E','u','r','o','p','e','a','n','\0'};
396 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
397 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
398 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
399 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
400 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
401 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
402 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
403 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
404 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
405 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
406 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
407 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
409 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
419 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
427 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
436 typedef struct tagFontSubst {
452 static struct list mappings_list = LIST_INIT( mappings_list );
454 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
456 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
458 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
460 /****************************************
461 * Notes on .fon files
463 * The fonts System, FixedSys and Terminal are special. There are typically multiple
464 * versions installed for different resolutions and codepages. Windows stores which one to use
465 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
467 * FIXEDFON.FON FixedSys
469 * OEMFONT.FON Terminal
470 * LogPixels Current dpi set by the display control panel applet
471 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
472 * also has a LogPixels value that appears to mirror this)
474 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
475 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
476 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
477 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
478 * so that makes sense.
480 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
481 * to be mapped into the registry on Windows 2000 at least).
484 * ega80woa.fon=ega80850.fon
485 * ega40woa.fon=ega40850.fon
486 * cga80woa.fon=cga80850.fon
487 * cga40woa.fon=cga40850.fon
490 #ifdef HAVE_CARBON_CARBON_H
491 static char *find_cache_dir(void)
495 static char cached_path[MAX_PATH];
496 static const char *wine = "/Wine", *fonts = "/Fonts";
498 if(*cached_path) return cached_path;
500 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
503 WARN("can't create cached data folder\n");
506 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
509 WARN("can't create cached data path\n");
513 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
515 ERR("Could not create full path\n");
519 strcat(cached_path, wine);
521 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
523 WARN("Couldn't mkdir %s\n", cached_path);
527 strcat(cached_path, fonts);
528 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
530 WARN("Couldn't mkdir %s\n", cached_path);
537 /******************************************************************
540 * Extracts individual TrueType font files from a Mac suitcase font
541 * and saves them into the user's caches directory (see
543 * Returns a NULL terminated array of filenames.
545 * We do this because they are apps that try to read ttf files
546 * themselves and they don't like Mac suitcase files.
548 static char **expand_mac_font(const char *path)
555 const char *filename;
559 unsigned int size, max_size;
562 TRACE("path %s\n", path);
564 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
567 WARN("failed to get ref\n");
571 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
574 TRACE("no data fork, so trying resource fork\n");
575 res_ref = FSOpenResFile(&ref, fsRdPerm);
578 TRACE("unable to open resource fork\n");
585 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
588 CloseResFile(res_ref);
592 out_dir = find_cache_dir();
594 filename = strrchr(path, '/');
595 if(!filename) filename = path;
598 /* output filename has the form out_dir/filename_%04x.ttf */
599 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
606 unsigned short *num_faces_ptr, num_faces, face;
609 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
611 fond = Get1IndResource(fond_res, idx);
613 TRACE("got fond resource %d\n", idx);
616 fam_rec = *(FamRec**)fond;
617 num_faces_ptr = (unsigned short *)(fam_rec + 1);
618 num_faces = GET_BE_WORD(*num_faces_ptr);
620 assoc = (AsscEntry*)(num_faces_ptr + 1);
621 TRACE("num faces %04x\n", num_faces);
622 for(face = 0; face < num_faces; face++, assoc++)
625 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
626 unsigned short size, font_id;
629 size = GET_BE_WORD(assoc->fontSize);
630 font_id = GET_BE_WORD(assoc->fontID);
633 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
637 TRACE("trying to load sfnt id %04x\n", font_id);
638 sfnt = GetResource(sfnt_res, font_id);
641 TRACE("can't get sfnt resource %04x\n", font_id);
645 output = HeapAlloc(GetProcessHeap(), 0, output_len);
650 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
652 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
653 if(fd != -1 || errno == EEXIST)
657 unsigned char *sfnt_data;
660 sfnt_data = *(unsigned char**)sfnt;
661 write(fd, sfnt_data, GetHandleSize(sfnt));
665 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
668 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
670 ret.array[ret.size++] = output;
674 WARN("unable to create %s\n", output);
675 HeapFree(GetProcessHeap(), 0, output);
678 ReleaseResource(sfnt);
681 ReleaseResource(fond);
684 CloseResFile(res_ref);
689 #endif /* HAVE_CARBON_CARBON_H */
691 static inline BOOL is_win9x(void)
693 return GetVersion() & 0x80000000;
696 This function builds an FT_Fixed from a float. It puts the integer part
697 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
698 It fails if the integer part of the float number is greater than SHORT_MAX.
700 static inline FT_Fixed FT_FixedFromFloat(float f)
703 unsigned short fract = (f - value) * 0xFFFF;
704 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
708 This function builds an FT_Fixed from a FIXED. It simply put f.value
709 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
711 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
713 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
717 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
722 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
723 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
725 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
726 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
728 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
730 if(face_name && strcmpiW(face_name, family->FamilyName))
732 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
736 file = strrchr(face->file, '/');
741 if(!strcasecmp(file, file_nameA))
743 HeapFree(GetProcessHeap(), 0, file_nameA);
748 HeapFree(GetProcessHeap(), 0, file_nameA);
752 static Family *find_family_from_name(const WCHAR *name)
756 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
758 if(!strcmpiW(family->FamilyName, name))
765 static void DumpSubstList(void)
769 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
771 if(psub->from.charset != -1 || psub->to.charset != -1)
772 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
773 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
775 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
776 debugstr_w(psub->to.name));
781 static LPWSTR strdupW(LPCWSTR p)
784 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
785 ret = HeapAlloc(GetProcessHeap(), 0, len);
790 static LPSTR strdupA(LPCSTR p)
793 DWORD len = (strlen(p) + 1);
794 ret = HeapAlloc(GetProcessHeap(), 0, len);
799 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
804 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
806 if(!strcmpiW(element->from.name, from_name) &&
807 (element->from.charset == from_charset ||
808 element->from.charset == -1))
815 #define ADD_FONT_SUBST_FORCE 1
817 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
819 FontSubst *from_exist, *to_exist;
821 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
823 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
825 list_remove(&from_exist->entry);
826 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
827 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
828 HeapFree(GetProcessHeap(), 0, from_exist);
834 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
838 HeapFree(GetProcessHeap(), 0, subst->to.name);
839 subst->to.name = strdupW(to_exist->to.name);
842 list_add_tail(subst_list, &subst->entry);
847 HeapFree(GetProcessHeap(), 0, subst->from.name);
848 HeapFree(GetProcessHeap(), 0, subst->to.name);
849 HeapFree(GetProcessHeap(), 0, subst);
853 static void split_subst_info(NameCs *nc, LPSTR str)
855 CHAR *p = strrchr(str, ',');
860 nc->charset = strtol(p+1, NULL, 10);
863 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
864 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
865 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
868 static void LoadSubstList(void)
872 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
876 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
877 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
878 &hkey) == ERROR_SUCCESS) {
880 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
881 &valuelen, &datalen, NULL, NULL);
883 valuelen++; /* returned value doesn't include room for '\0' */
884 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
885 data = HeapAlloc(GetProcessHeap(), 0, datalen);
889 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
890 &dlen) == ERROR_SUCCESS) {
891 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
893 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
894 split_subst_info(&psub->from, value);
895 split_subst_info(&psub->to, data);
897 /* Win 2000 doesn't allow mapping between different charsets
898 or mapping of DEFAULT_CHARSET */
899 if((psub->to.charset != psub->from.charset) ||
900 psub->to.charset == DEFAULT_CHARSET) {
901 HeapFree(GetProcessHeap(), 0, psub->to.name);
902 HeapFree(GetProcessHeap(), 0, psub->from.name);
903 HeapFree(GetProcessHeap(), 0, psub);
905 add_font_subst(&font_subst_list, psub, 0);
907 /* reset dlen and vlen */
911 HeapFree(GetProcessHeap(), 0, data);
912 HeapFree(GetProcessHeap(), 0, value);
917 static WCHAR *get_familyname(FT_Face ft_face)
919 WCHAR *family = NULL;
921 FT_UInt num_names, name_index, i;
923 if(FT_IS_SFNT(ft_face))
925 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
927 for(name_index = 0; name_index < num_names; name_index++)
929 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
931 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
932 (name.language_id == GetUserDefaultLCID()) &&
933 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
934 (name.encoding_id == TT_MS_ID_UNICODE_CS))
936 /* String is not nul terminated and string_len is a byte length. */
937 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
938 for(i = 0; i < name.string_len / 2; i++)
940 WORD *tmp = (WORD *)&name.string[i * 2];
941 family[i] = GET_BE_WORD(*tmp);
945 TRACE("Got localised name %s\n", debugstr_w(family));
956 /*****************************************************************
959 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
960 * of FreeType that don't export this function.
963 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
968 /* If the FT_Load_Sfnt_Table function is there we'll use it */
969 if(pFT_Load_Sfnt_Table)
971 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
973 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
974 else /* Do it the hard way */
976 TT_Face tt_face = (TT_Face) ft_face;
977 SFNT_Interface *sfnt;
978 if (FT_Version.major==2 && FT_Version.minor==0)
981 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
985 /* A field was added in the middle of the structure in 2.1.x */
986 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
988 err = sfnt->load_any(tt_face, table, offset, buf, len);
996 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
997 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
998 "Please upgrade your freetype library.\n");
1001 err = FT_Err_Unimplemented_Feature;
1008 #define ADDFONT_EXTERNAL_FONT 0x01
1009 #define ADDFONT_FORCE_BITMAP 0x02
1010 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1014 TT_Header *pHeader = NULL;
1015 WCHAR *english_family, *localised_family, *StyleW;
1019 struct list *family_elem_ptr, *face_elem_ptr;
1021 FT_Long face_index = 0, num_faces;
1022 #ifdef HAVE_FREETYPE_FTWINFNT_H
1023 FT_WinFNT_HeaderRec winfnt_header;
1025 int i, bitmap_num, internal_leading;
1028 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1029 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1031 #ifdef HAVE_CARBON_CARBON_H
1032 if(file && !fake_family)
1034 char **mac_list = expand_mac_font(file);
1037 BOOL had_one = FALSE;
1039 for(cursor = mac_list; *cursor; cursor++)
1042 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1043 HeapFree(GetProcessHeap(), 0, *cursor);
1045 HeapFree(GetProcessHeap(), 0, mac_list);
1050 #endif /* HAVE_CARBON_CARBON_H */
1053 char *family_name = fake_family;
1057 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1058 err = pFT_New_Face(library, file, face_index, &ft_face);
1061 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1062 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1066 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1070 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*/
1071 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1072 pFT_Done_Face(ft_face);
1076 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1077 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1078 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1079 pFT_Done_Face(ft_face);
1083 if(FT_IS_SFNT(ft_face))
1085 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1086 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1087 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1089 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1090 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1091 pFT_Done_Face(ft_face);
1095 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1096 we don't want to load these. */
1097 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1101 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1103 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1104 pFT_Done_Face(ft_face);
1110 if(!ft_face->family_name || !ft_face->style_name) {
1111 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1112 pFT_Done_Face(ft_face);
1118 localised_family = get_familyname(ft_face);
1119 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1121 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1122 HeapFree(GetProcessHeap(), 0, localised_family);
1123 num_faces = ft_face->num_faces;
1124 pFT_Done_Face(ft_face);
1127 HeapFree(GetProcessHeap(), 0, localised_family);
1131 family_name = ft_face->family_name;
1135 My_FT_Bitmap_Size *size = NULL;
1138 if(!FT_IS_SCALABLE(ft_face))
1139 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1141 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1142 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1143 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1145 localised_family = NULL;
1147 localised_family = get_familyname(ft_face);
1148 if(localised_family && !strcmpW(localised_family, english_family)) {
1149 HeapFree(GetProcessHeap(), 0, localised_family);
1150 localised_family = NULL;
1155 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1156 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1157 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1162 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1163 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1164 list_init(&family->faces);
1165 list_add_tail(&font_list, &family->entry);
1167 if(localised_family) {
1168 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1169 subst->from.name = strdupW(english_family);
1170 subst->from.charset = -1;
1171 subst->to.name = strdupW(localised_family);
1172 subst->to.charset = -1;
1173 add_font_subst(&font_subst_list, subst, 0);
1176 HeapFree(GetProcessHeap(), 0, localised_family);
1177 HeapFree(GetProcessHeap(), 0, english_family);
1179 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1180 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1181 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1183 internal_leading = 0;
1184 memset(&fs, 0, sizeof(fs));
1186 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1188 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1189 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1190 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1191 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1192 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1193 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1194 if(pOS2->version == 0) {
1197 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1198 fs.fsCsb[0] |= FS_LATIN1;
1200 fs.fsCsb[0] |= FS_SYMBOL;
1203 #ifdef HAVE_FREETYPE_FTWINFNT_H
1204 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1206 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1207 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1208 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1209 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1210 internal_leading = winfnt_header.internal_leading;
1214 face_elem_ptr = list_head(&family->faces);
1215 while(face_elem_ptr) {
1216 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1217 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1218 if(!strcmpW(face->StyleName, StyleW) &&
1219 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1220 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1221 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1222 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1225 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1226 HeapFree(GetProcessHeap(), 0, StyleW);
1227 pFT_Done_Face(ft_face);
1230 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1231 TRACE("Original font is newer so skipping this one\n");
1232 HeapFree(GetProcessHeap(), 0, StyleW);
1233 pFT_Done_Face(ft_face);
1236 TRACE("Replacing original with this one\n");
1237 list_remove(&face->entry);
1238 HeapFree(GetProcessHeap(), 0, face->file);
1239 HeapFree(GetProcessHeap(), 0, face->StyleName);
1240 HeapFree(GetProcessHeap(), 0, face);
1245 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1246 face->cached_enum_data = NULL;
1247 list_add_tail(&family->faces, &face->entry);
1248 face->StyleName = StyleW;
1251 face->file = strdupA(file);
1252 face->font_data_ptr = NULL;
1253 face->font_data_size = 0;
1258 face->font_data_ptr = font_data_ptr;
1259 face->font_data_size = font_data_size;
1261 face->face_index = face_index;
1262 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1263 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1264 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1265 face->family = family;
1266 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1267 memcpy(&face->fs, &fs, sizeof(face->fs));
1268 memset(&face->fs_links, 0, sizeof(face->fs_links));
1270 if(FT_IS_SCALABLE(ft_face)) {
1271 memset(&face->size, 0, sizeof(face->size));
1272 face->scalable = TRUE;
1274 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1275 size->height, size->width, size->size >> 6,
1276 size->x_ppem >> 6, size->y_ppem >> 6);
1277 face->size.height = size->height;
1278 face->size.width = size->width;
1279 face->size.size = size->size;
1280 face->size.x_ppem = size->x_ppem;
1281 face->size.y_ppem = size->y_ppem;
1282 face->size.internal_leading = internal_leading;
1283 face->scalable = FALSE;
1286 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1288 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1290 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1291 face->ntmFlags = NTM_PS_OPENTYPE;
1296 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1297 face->fs.fsCsb[0], face->fs.fsCsb[1],
1298 face->fs.fsUsb[0], face->fs.fsUsb[1],
1299 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1302 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1303 for(i = 0; i < ft_face->num_charmaps; i++) {
1304 switch(ft_face->charmaps[i]->encoding) {
1305 case FT_ENCODING_UNICODE:
1306 case FT_ENCODING_APPLE_ROMAN:
1307 face->fs.fsCsb[0] |= FS_LATIN1;
1309 case FT_ENCODING_MS_SYMBOL:
1310 face->fs.fsCsb[0] |= FS_SYMBOL;
1318 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1319 have_installed_roman_font = TRUE;
1320 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1322 num_faces = ft_face->num_faces;
1323 pFT_Done_Face(ft_face);
1324 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1325 debugstr_w(StyleW));
1326 } while(num_faces > ++face_index);
1330 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1332 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1335 static void DumpFontList(void)
1339 struct list *family_elem_ptr, *face_elem_ptr;
1341 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1342 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1343 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1344 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1345 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1346 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1348 TRACE(" %d", face->size.height);
1355 /***********************************************************
1356 * The replacement list is a way to map an entire font
1357 * family onto another family. For example adding
1359 * [HKCU\Software\Wine\Fonts\Replacements]
1360 * "Wingdings"="Winedings"
1362 * would enumerate the Winedings font both as Winedings and
1363 * Wingdings. However if a real Wingdings font is present the
1364 * replacement does not take place.
1367 static void LoadReplaceList(void)
1370 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1375 struct list *family_elem_ptr, *face_elem_ptr;
1378 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1379 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1381 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1382 &valuelen, &datalen, NULL, NULL);
1384 valuelen++; /* returned value doesn't include room for '\0' */
1385 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1386 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1390 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1391 &dlen) == ERROR_SUCCESS) {
1392 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1393 /* "NewName"="Oldname" */
1394 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1396 /* Find the old family and hence all of the font files
1398 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1399 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1400 if(!strcmpiW(family->FamilyName, data)) {
1401 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1402 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1403 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1404 debugstr_w(face->StyleName), familyA);
1405 /* Now add a new entry with the new family name */
1406 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1411 /* reset dlen and vlen */
1415 HeapFree(GetProcessHeap(), 0, data);
1416 HeapFree(GetProcessHeap(), 0, value);
1421 /*************************************************************
1424 static BOOL init_system_links(void)
1426 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1427 'W','i','n','d','o','w','s',' ','N','T','\\',
1428 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1429 'S','y','s','t','e','m','L','i','n','k',0};
1432 DWORD type, max_val, max_data, val_len, data_len, index;
1433 WCHAR *value, *data;
1434 WCHAR *entry, *next;
1435 SYSTEM_LINKS *font_link, *system_font_link;
1436 CHILD_FONT *child_font;
1437 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1438 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1439 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1445 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1447 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1448 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1449 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1450 val_len = max_val + 1;
1451 data_len = max_data;
1453 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1455 TRACE("%s:\n", debugstr_w(value));
1457 memset(&fs, 0, sizeof(fs));
1458 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1459 psub = get_font_subst(&font_subst_list, value, -1);
1460 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1461 list_init(&font_link->links);
1462 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1465 CHILD_FONT *child_font;
1467 TRACE("\t%s\n", debugstr_w(entry));
1469 next = entry + strlenW(entry) + 1;
1471 face_name = strchrW(entry, ',');
1475 while(isspaceW(*face_name))
1478 psub = get_font_subst(&font_subst_list, face_name, -1);
1480 face_name = psub->to.name;
1482 face = find_face_from_filename(entry, face_name);
1485 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1489 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1490 child_font->face = face;
1491 child_font->font = NULL;
1492 fs.fsCsb[0] |= face->fs.fsCsb[0];
1493 fs.fsCsb[1] |= face->fs.fsCsb[1];
1494 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1495 list_add_tail(&font_link->links, &child_font->entry);
1497 family = find_family_from_name(font_link->font_name);
1500 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1502 memcpy(&face->fs_links, &fs, sizeof(fs));
1505 list_add_tail(&system_links, &font_link->entry);
1506 val_len = max_val + 1;
1507 data_len = max_data;
1510 HeapFree(GetProcessHeap(), 0, value);
1511 HeapFree(GetProcessHeap(), 0, data);
1515 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1518 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1519 system_font_link->font_name = strdupW(System);
1520 list_init(&system_font_link->links);
1522 face = find_face_from_filename(tahoma_ttf, Tahoma);
1525 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1526 child_font->face = face;
1527 child_font->font = NULL;
1528 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1529 list_add_tail(&system_font_link->links, &child_font->entry);
1531 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1533 if(!strcmpiW(font_link->font_name, Tahoma))
1535 CHILD_FONT *font_link_entry;
1536 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1538 CHILD_FONT *new_child;
1539 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1540 new_child->face = font_link_entry->face;
1541 new_child->font = NULL;
1542 list_add_tail(&system_font_link->links, &new_child->entry);
1547 list_add_tail(&system_links, &system_font_link->entry);
1551 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1554 struct dirent *dent;
1555 char path[MAX_PATH];
1557 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1559 dir = opendir(dirname);
1561 WARN("Can't open directory %s\n", debugstr_a(dirname));
1564 while((dent = readdir(dir)) != NULL) {
1565 struct stat statbuf;
1567 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1570 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1572 sprintf(path, "%s/%s", dirname, dent->d_name);
1574 if(stat(path, &statbuf) == -1)
1576 WARN("Can't stat %s\n", debugstr_a(path));
1579 if(S_ISDIR(statbuf.st_mode))
1580 ReadFontDir(path, external_fonts);
1582 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1588 static void load_fontconfig_fonts(void)
1590 #ifdef SONAME_LIBFONTCONFIG
1591 void *fc_handle = NULL;
1600 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1602 TRACE("Wine cannot find the fontconfig library (%s).\n",
1603 SONAME_LIBFONTCONFIG);
1606 #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;}
1607 LOAD_FUNCPTR(FcConfigGetCurrent);
1608 LOAD_FUNCPTR(FcFontList);
1609 LOAD_FUNCPTR(FcFontSetDestroy);
1610 LOAD_FUNCPTR(FcInit);
1611 LOAD_FUNCPTR(FcObjectSetAdd);
1612 LOAD_FUNCPTR(FcObjectSetCreate);
1613 LOAD_FUNCPTR(FcObjectSetDestroy);
1614 LOAD_FUNCPTR(FcPatternCreate);
1615 LOAD_FUNCPTR(FcPatternDestroy);
1616 LOAD_FUNCPTR(FcPatternGetBool);
1617 LOAD_FUNCPTR(FcPatternGetString);
1620 if(!pFcInit()) return;
1622 config = pFcConfigGetCurrent();
1623 pat = pFcPatternCreate();
1624 os = pFcObjectSetCreate();
1625 pFcObjectSetAdd(os, FC_FILE);
1626 pFcObjectSetAdd(os, FC_SCALABLE);
1627 fontset = pFcFontList(config, pat, os);
1628 if(!fontset) return;
1629 for(i = 0; i < fontset->nfont; i++) {
1632 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1634 TRACE("fontconfig: %s\n", file);
1636 /* We're just interested in OT/TT fonts for now, so this hack just
1637 picks up the scalable fonts without extensions .pf[ab] to save time
1638 loading every other font */
1640 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1642 TRACE("not scalable\n");
1646 len = strlen( file );
1647 if(len < 4) continue;
1648 ext = &file[ len - 3 ];
1649 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1650 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1652 pFcFontSetDestroy(fontset);
1653 pFcObjectSetDestroy(os);
1654 pFcPatternDestroy(pat);
1660 static BOOL load_font_from_data_dir(LPCWSTR file)
1663 const char *data_dir = wine_get_data_dir();
1665 if (!data_dir) data_dir = wine_get_build_dir();
1672 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1674 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1676 strcpy(unix_name, data_dir);
1677 strcat(unix_name, "/fonts/");
1679 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1681 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1682 HeapFree(GetProcessHeap(), 0, unix_name);
1687 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1689 static const WCHAR slashW[] = {'\\','\0'};
1691 WCHAR windowsdir[MAX_PATH];
1694 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1695 strcatW(windowsdir, fontsW);
1696 strcatW(windowsdir, slashW);
1697 strcatW(windowsdir, file);
1698 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1699 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1700 HeapFree(GetProcessHeap(), 0, unixname);
1705 static void load_system_fonts(void)
1708 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1709 const WCHAR * const *value;
1711 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1714 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1715 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1716 strcatW(windowsdir, fontsW);
1717 for(value = SystemFontValues; *value; value++) {
1718 dlen = sizeof(data);
1719 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1723 sprintfW(pathW, fmtW, windowsdir, data);
1724 if((unixname = wine_get_unix_file_name(pathW))) {
1725 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1726 HeapFree(GetProcessHeap(), 0, unixname);
1729 load_font_from_data_dir(data);
1736 /*************************************************************
1738 * This adds registry entries for any externally loaded fonts
1739 * (fonts from fontconfig or FontDirs). It also deletes entries
1740 * of no longer existing fonts.
1743 static void update_reg_entries(void)
1745 HKEY winkey = 0, externalkey = 0;
1748 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1751 struct list *family_elem_ptr, *face_elem_ptr;
1753 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1754 static const WCHAR spaceW[] = {' ', '\0'};
1757 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1758 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1759 ERR("Can't create Windows font reg key\n");
1762 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1763 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1764 ERR("Can't create external font reg key\n");
1768 /* Delete all external fonts added last time */
1770 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1771 &valuelen, &datalen, NULL, NULL);
1772 valuelen++; /* returned value doesn't include room for '\0' */
1773 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1774 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1776 dlen = datalen * sizeof(WCHAR);
1779 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1780 &dlen) == ERROR_SUCCESS) {
1782 RegDeleteValueW(winkey, valueW);
1783 /* reset dlen and vlen */
1787 HeapFree(GetProcessHeap(), 0, data);
1788 HeapFree(GetProcessHeap(), 0, valueW);
1790 /* Delete the old external fonts key */
1791 RegCloseKey(externalkey);
1793 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1795 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1796 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1797 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1798 ERR("Can't create external font reg key\n");
1802 /* enumerate the fonts and add external ones to the two keys */
1804 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1805 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1806 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1807 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1808 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1809 if(!face->external) continue;
1811 if(strcmpiW(face->StyleName, RegularW))
1812 len = len_fam + strlenW(face->StyleName) + 1;
1813 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1814 strcpyW(valueW, family->FamilyName);
1815 if(len != len_fam) {
1816 strcatW(valueW, spaceW);
1817 strcatW(valueW, face->StyleName);
1819 strcatW(valueW, TrueType);
1820 if((path = strrchr(face->file, '/')) == NULL)
1824 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1826 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1827 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1828 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1829 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1831 HeapFree(GetProcessHeap(), 0, file);
1832 HeapFree(GetProcessHeap(), 0, valueW);
1837 RegCloseKey(externalkey);
1839 RegCloseKey(winkey);
1844 /*************************************************************
1845 * WineEngAddFontResourceEx
1848 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1851 if (ft_handle) /* do it only if we have freetype up and running */
1856 FIXME("Ignoring flags %x\n", flags);
1858 if((unixname = wine_get_unix_file_name(file)))
1860 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1861 HeapFree(GetProcessHeap(), 0, unixname);
1863 if (!ret && !strchrW(file, '\\')) {
1864 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
1865 ret = load_font_from_winfonts_dir(file);
1867 /* Try in datadir/fonts (or builddir/fonts),
1868 * needed for Magic the Gathering Online
1870 ret = load_font_from_data_dir(file);
1877 /*************************************************************
1878 * WineEngAddFontMemResourceEx
1881 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
1883 if (ft_handle) /* do it only if we have freetype up and running */
1885 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
1887 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
1888 memcpy(pFontCopy, pbFont, cbFont);
1890 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
1894 TRACE("AddFontToList failed\n");
1895 HeapFree(GetProcessHeap(), 0, pFontCopy);
1898 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1899 * For now return something unique but quite random
1901 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
1902 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
1909 /*************************************************************
1910 * WineEngRemoveFontResourceEx
1913 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1919 static const struct nls_update_font_list
1921 UINT ansi_cp, oem_cp;
1922 const char *oem, *fixed, *system;
1923 const char *courier, *serif, *small, *sserif;
1924 /* these are for font substitute */
1925 const char *shelldlg, *tmsrmn;
1926 } nls_update_font_list[] =
1928 /* Latin 1 (United States) */
1929 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1930 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1931 "Tahoma","Times New Roman",
1933 /* Latin 1 (Multilingual) */
1934 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1935 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1936 "Tahoma","Times New Roman", /* FIXME unverified */
1938 /* Eastern Europe */
1939 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1940 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1941 "Tahoma","Times New Roman", /* FIXME unverified */
1944 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1945 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1946 "Tahoma","Times New Roman", /* FIXME unverified */
1949 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1950 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1951 "Tahoma","Times New Roman", /* FIXME unverified */
1954 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1955 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1956 "Tahoma","Times New Roman", /* FIXME unverified */
1959 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1960 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1961 "Tahoma","Times New Roman", /* FIXME unverified */
1964 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1965 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1966 "Tahoma","Times New Roman", /* FIXME unverified */
1969 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1970 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1971 "Tahoma","Times New Roman", /* FIXME unverified */
1974 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1975 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1976 "Tahoma","Times New Roman", /* FIXME unverified */
1979 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1980 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1981 "Tahoma","Times New Roman", /* FIXME unverified */
1984 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1985 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1986 "MS UI Gothic","MS Serif",
1988 /* Chinese Simplified */
1989 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1990 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1991 "Tahoma", "Times New Roman", /* FIXME unverified */
1994 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1995 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1998 /* Chinese Traditional */
1999 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2000 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2001 "Tahoma", "Times New Roman", /* FIXME unverified */
2005 static inline HKEY create_fonts_NT_registry_key(void)
2009 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2010 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2014 static inline HKEY create_fonts_9x_registry_key(void)
2018 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2019 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2023 static inline HKEY create_config_fonts_registry_key(void)
2027 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2028 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2032 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2034 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2035 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2036 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2037 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2040 static void update_font_info(void)
2042 char buf[40], cpbuf[40];
2045 UINT i, ansi_cp = 0, oem_cp = 0;
2047 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2050 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2051 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2052 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2053 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2054 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2057 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2059 if (!strcmp( buf, cpbuf )) /* already set correctly */
2064 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2066 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2068 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2071 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2073 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2074 nls_update_font_list[i].oem_cp == oem_cp)
2078 hkey = create_config_fonts_registry_key();
2079 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2080 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2081 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2084 hkey = create_fonts_NT_registry_key();
2085 add_font_list(hkey, &nls_update_font_list[i]);
2088 hkey = create_fonts_9x_registry_key();
2089 add_font_list(hkey, &nls_update_font_list[i]);
2092 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2094 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2095 strlen(nls_update_font_list[i].shelldlg)+1);
2096 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2097 strlen(nls_update_font_list[i].tmsrmn)+1);
2103 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2106 /*************************************************************
2109 * Initialize FreeType library and create a list of available faces
2111 BOOL WineEngInit(void)
2113 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2114 static const WCHAR pathW[] = {'P','a','t','h',0};
2116 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2118 WCHAR windowsdir[MAX_PATH];
2121 const char *data_dir;
2125 /* update locale dependent font info in registry */
2128 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2131 "Wine cannot find the FreeType font library. To enable Wine to\n"
2132 "use TrueType fonts please install a version of FreeType greater than\n"
2133 "or equal to 2.0.5.\n"
2134 "http://www.freetype.org\n");
2138 #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;}
2140 LOAD_FUNCPTR(FT_Vector_Unit)
2141 LOAD_FUNCPTR(FT_Done_Face)
2142 LOAD_FUNCPTR(FT_Get_Char_Index)
2143 LOAD_FUNCPTR(FT_Get_Module)
2144 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2145 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2146 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2147 LOAD_FUNCPTR(FT_Init_FreeType)
2148 LOAD_FUNCPTR(FT_Load_Glyph)
2149 LOAD_FUNCPTR(FT_Matrix_Multiply)
2150 LOAD_FUNCPTR(FT_MulFix)
2151 LOAD_FUNCPTR(FT_New_Face)
2152 LOAD_FUNCPTR(FT_New_Memory_Face)
2153 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2154 LOAD_FUNCPTR(FT_Outline_Transform)
2155 LOAD_FUNCPTR(FT_Outline_Translate)
2156 LOAD_FUNCPTR(FT_Select_Charmap)
2157 LOAD_FUNCPTR(FT_Set_Charmap)
2158 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2159 LOAD_FUNCPTR(FT_Vector_Transform)
2162 /* Don't warn if this one is missing */
2163 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2164 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2165 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2166 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2167 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2168 #ifdef HAVE_FREETYPE_FTWINFNT_H
2169 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2171 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2172 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2173 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2174 <= 2.0.3 has FT_Sqrt64 */
2178 if(pFT_Init_FreeType(&library) != 0) {
2179 ERR("Can't init FreeType library\n");
2180 wine_dlclose(ft_handle, NULL, 0);
2184 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2185 if (pFT_Library_Version)
2187 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2189 if (FT_Version.major<=0)
2195 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2196 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2197 ((FT_Version.minor << 8) & 0x00ff00) |
2198 ((FT_Version.patch ) & 0x0000ff);
2200 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2201 ERR("Failed to create font mutex\n");
2204 WaitForSingleObject(font_mutex, INFINITE);
2206 /* load the system bitmap fonts */
2207 load_system_fonts();
2209 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2210 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2211 strcatW(windowsdir, fontsW);
2212 if((unixname = wine_get_unix_file_name(windowsdir)))
2214 ReadFontDir(unixname, FALSE);
2215 HeapFree(GetProcessHeap(), 0, unixname);
2218 /* load the system truetype fonts */
2219 data_dir = wine_get_data_dir();
2220 if (!data_dir) data_dir = wine_get_build_dir();
2221 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2222 strcpy(unixname, data_dir);
2223 strcat(unixname, "/fonts/");
2224 ReadFontDir(unixname, TRUE);
2225 HeapFree(GetProcessHeap(), 0, unixname);
2228 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2229 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2230 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2232 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2233 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2234 &hkey) == ERROR_SUCCESS) {
2236 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2237 &valuelen, &datalen, NULL, NULL);
2239 valuelen++; /* returned value doesn't include room for '\0' */
2240 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2241 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2244 dlen = datalen * sizeof(WCHAR);
2246 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2247 &dlen) == ERROR_SUCCESS) {
2248 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2250 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2252 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2253 HeapFree(GetProcessHeap(), 0, unixname);
2256 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2258 WCHAR pathW[MAX_PATH];
2259 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2262 sprintfW(pathW, fmtW, windowsdir, data);
2263 if((unixname = wine_get_unix_file_name(pathW)))
2265 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2266 HeapFree(GetProcessHeap(), 0, unixname);
2269 load_font_from_data_dir(data);
2271 /* reset dlen and vlen */
2276 HeapFree(GetProcessHeap(), 0, data);
2277 HeapFree(GetProcessHeap(), 0, valueW);
2281 load_fontconfig_fonts();
2283 /* then look in any directories that we've specified in the config file */
2284 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2285 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2291 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2293 len += sizeof(WCHAR);
2294 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2295 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2297 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2298 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2299 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2300 TRACE( "got font path %s\n", debugstr_a(valueA) );
2304 LPSTR next = strchr( ptr, ':' );
2305 if (next) *next++ = 0;
2306 ReadFontDir( ptr, TRUE );
2309 HeapFree( GetProcessHeap(), 0, valueA );
2311 HeapFree( GetProcessHeap(), 0, valueW );
2320 update_reg_entries();
2322 init_system_links();
2324 ReleaseMutex(font_mutex);
2328 "Wine cannot find certain functions that it needs inside the FreeType\n"
2329 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2330 "FreeType to at least version 2.0.5.\n"
2331 "http://www.freetype.org\n");
2332 wine_dlclose(ft_handle, NULL, 0);
2338 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2341 TT_HoriHeader *pHori;
2345 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2346 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2348 if(height == 0) height = 16;
2350 /* Calc. height of EM square:
2352 * For +ve lfHeight we have
2353 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2354 * Re-arranging gives:
2355 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2357 * For -ve lfHeight we have
2359 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2360 * with il = winAscent + winDescent - units_per_em]
2365 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2366 ppem = ft_face->units_per_EM * height /
2367 (pHori->Ascender - pHori->Descender);
2369 ppem = ft_face->units_per_EM * height /
2370 (pOS2->usWinAscent + pOS2->usWinDescent);
2378 static struct font_mapping *map_font_file( const char *name )
2380 struct font_mapping *mapping;
2384 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2385 if (fstat( fd, &st ) == -1) goto error;
2387 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2389 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2391 mapping->refcount++;
2396 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2399 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2402 if (mapping->data == MAP_FAILED)
2404 HeapFree( GetProcessHeap(), 0, mapping );
2407 mapping->refcount = 1;
2408 mapping->dev = st.st_dev;
2409 mapping->ino = st.st_ino;
2410 mapping->size = st.st_size;
2411 list_add_tail( &mappings_list, &mapping->entry );
2419 static void unmap_font_file( struct font_mapping *mapping )
2421 if (!--mapping->refcount)
2423 list_remove( &mapping->entry );
2424 munmap( mapping->data, mapping->size );
2425 HeapFree( GetProcessHeap(), 0, mapping );
2429 static LONG load_VDMX(GdiFont*, LONG);
2431 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2438 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2442 if (!(font->mapping = map_font_file( face->file )))
2444 WARN("failed to map %s\n", debugstr_a(face->file));
2447 data_ptr = font->mapping->data;
2448 data_size = font->mapping->size;
2452 data_ptr = face->font_data_ptr;
2453 data_size = face->font_data_size;
2456 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2458 ERR("FT_New_Face rets %d\n", err);
2462 /* set it here, as load_VDMX needs it */
2463 font->ft_face = ft_face;
2465 if(FT_IS_SCALABLE(ft_face)) {
2466 /* load the VDMX table if we have one */
2467 font->ppem = load_VDMX(font, height);
2469 font->ppem = calc_ppem_for_height(ft_face, height);
2471 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2472 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2474 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2475 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2481 static int get_nearest_charset(Face *face, int *cp)
2483 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2484 a single face with the requested charset. The idea is to check if
2485 the selected font supports the current ANSI codepage, if it does
2486 return the corresponding charset, else return the first charset */
2489 int acp = GetACP(), i;
2493 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2494 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2495 return csi.ciCharset;
2497 for(i = 0; i < 32; i++) {
2499 if(face->fs.fsCsb[0] & fs0) {
2500 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2502 return csi.ciCharset;
2505 FIXME("TCI failing on %x\n", fs0);
2509 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2510 face->fs.fsCsb[0], face->file);
2512 return DEFAULT_CHARSET;
2515 static GdiFont *alloc_font(void)
2517 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2519 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2520 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2522 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2523 ret->total_kern_pairs = (DWORD)-1;
2524 ret->kern_pairs = NULL;
2525 list_init(&ret->hfontlist);
2526 list_init(&ret->child_fonts);
2530 static void free_font(GdiFont *font)
2532 struct list *cursor, *cursor2;
2535 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2537 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2538 struct list *first_hfont;
2539 HFONTLIST *hfontlist;
2540 list_remove(cursor);
2543 first_hfont = list_head(&child->font->hfontlist);
2544 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2545 DeleteObject(hfontlist->hfont);
2546 HeapFree(GetProcessHeap(), 0, hfontlist);
2547 free_font(child->font);
2549 HeapFree(GetProcessHeap(), 0, child);
2552 if (font->ft_face) pFT_Done_Face(font->ft_face);
2553 if (font->mapping) unmap_font_file( font->mapping );
2554 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2555 HeapFree(GetProcessHeap(), 0, font->potm);
2556 HeapFree(GetProcessHeap(), 0, font->name);
2557 for (i = 0; i < font->gmsize; i++)
2558 HeapFree(GetProcessHeap(),0,font->gm[i]);
2559 HeapFree(GetProcessHeap(), 0, font->gm);
2560 HeapFree(GetProcessHeap(), 0, font);
2564 /*************************************************************
2567 * load the vdmx entry for the specified height
2570 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2571 ( ( (FT_ULong)_x4 << 24 ) | \
2572 ( (FT_ULong)_x3 << 16 ) | \
2573 ( (FT_ULong)_x2 << 8 ) | \
2576 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2591 static LONG load_VDMX(GdiFont *font, LONG height)
2595 BYTE devXRatio, devYRatio;
2596 USHORT numRecs, numRatios;
2597 DWORD result, offset = -1;
2601 /* For documentation on VDMX records, see
2602 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2605 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2607 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2610 /* FIXME: need the real device aspect ratio */
2614 numRecs = GET_BE_WORD(hdr[1]);
2615 numRatios = GET_BE_WORD(hdr[2]);
2617 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2618 for(i = 0; i < numRatios; i++) {
2621 offset = (3 * 2) + (i * sizeof(Ratios));
2622 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2625 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2627 if((ratio.xRatio == 0 &&
2628 ratio.yStartRatio == 0 &&
2629 ratio.yEndRatio == 0) ||
2630 (devXRatio == ratio.xRatio &&
2631 devYRatio >= ratio.yStartRatio &&
2632 devYRatio <= ratio.yEndRatio))
2634 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2635 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2636 offset = GET_BE_WORD(tmp);
2642 FIXME("No suitable ratio found\n");
2646 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2648 BYTE startsz, endsz;
2651 recs = GET_BE_WORD(group.recs);
2652 startsz = group.startsz;
2653 endsz = group.endsz;
2655 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2657 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2658 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2659 if(result == GDI_ERROR) {
2660 FIXME("Failed to retrieve vTable\n");
2665 for(i = 0; i < recs; i++) {
2666 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2667 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2668 ppem = GET_BE_WORD(vTable[i * 3]);
2670 if(yMax + -yMin == height) {
2673 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2676 if(yMax + -yMin > height) {
2679 goto end; /* failed */
2681 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2682 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2683 ppem = GET_BE_WORD(vTable[i * 3]);
2684 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2690 TRACE("ppem not found for height %d\n", height);
2694 if(ppem < startsz || ppem > endsz)
2697 for(i = 0; i < recs; i++) {
2699 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2701 if(yPelHeight > ppem)
2704 if(yPelHeight == ppem) {
2705 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2706 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2707 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2713 HeapFree(GetProcessHeap(), 0, vTable);
2719 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2721 if(font->font_desc.hash != fd->hash) return TRUE;
2722 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2723 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2724 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2725 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2728 static void calc_hash(FONT_DESC *pfd)
2730 DWORD hash = 0, *ptr, two_chars;
2734 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2736 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2738 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2740 pwc = (WCHAR *)&two_chars;
2742 *pwc = toupperW(*pwc);
2744 *pwc = toupperW(*pwc);
2748 hash ^= !pfd->can_use_bitmap;
2753 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2758 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2760 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2761 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2762 fd.can_use_bitmap = can_use_bitmap;
2765 /* try the in-use list */
2766 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2767 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2768 if(!fontcmp(ret, &fd)) {
2769 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2770 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2771 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2772 if(hflist->hfont == hfont)
2775 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2776 hflist->hfont = hfont;
2777 list_add_head(&ret->hfontlist, &hflist->entry);
2782 /* then the unused list */
2783 font_elem_ptr = list_head(&unused_gdi_font_list);
2784 while(font_elem_ptr) {
2785 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2786 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2787 if(!fontcmp(ret, &fd)) {
2788 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2789 assert(list_empty(&ret->hfontlist));
2790 TRACE("Found %p in unused list\n", ret);
2791 list_remove(&ret->entry);
2792 list_add_head(&gdi_font_list, &ret->entry);
2793 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2794 hflist->hfont = hfont;
2795 list_add_head(&ret->hfontlist, &hflist->entry);
2803 /*************************************************************
2804 * create_child_font_list
2806 static BOOL create_child_font_list(GdiFont *font)
2809 SYSTEM_LINKS *font_link;
2810 CHILD_FONT *font_link_entry, *new_child;
2812 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2814 if(!strcmpW(font_link->font_name, font->name))
2816 TRACE("found entry in system list\n");
2817 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2819 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2820 new_child->face = font_link_entry->face;
2821 new_child->font = NULL;
2822 list_add_tail(&font->child_fonts, &new_child->entry);
2823 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2833 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2835 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2837 if (pFT_Set_Charmap)
2840 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2842 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2844 for (i = 0; i < ft_face->num_charmaps; i++)
2846 if (ft_face->charmaps[i]->encoding == encoding)
2848 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2849 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2851 switch (ft_face->charmaps[i]->platform_id)
2854 cmap_def = ft_face->charmaps[i];
2856 case 0: /* Apple Unicode */
2857 cmap0 = ft_face->charmaps[i];
2859 case 1: /* Macintosh */
2860 cmap1 = ft_face->charmaps[i];
2863 cmap2 = ft_face->charmaps[i];
2865 case 3: /* Microsoft */
2866 cmap3 = ft_face->charmaps[i];
2871 if (cmap3) /* prefer Microsoft cmap table */
2872 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2874 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2876 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2878 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2880 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2882 return ft_err == FT_Err_Ok;
2885 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
2888 /*************************************************************
2889 * WineEngCreateFontInstance
2892 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2895 Face *face, *best, *best_bitmap;
2896 Family *family, *last_resort_family;
2897 struct list *family_elem_ptr, *face_elem_ptr;
2898 INT height, width = 0;
2899 unsigned int score = 0, new_score;
2900 signed int diff = 0, newdiff;
2901 BOOL bd, it, can_use_bitmap;
2906 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2908 struct list *first_hfont = list_head(&ret->hfontlist);
2909 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2910 if(hflist->hfont == hfont)
2914 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2915 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2917 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2918 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2919 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2922 /* check the cache first */
2923 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2924 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2928 TRACE("not in cache\n");
2929 if(list_empty(&font_list)) /* No fonts installed */
2931 TRACE("No fonts installed\n");
2934 if(!have_installed_roman_font)
2936 TRACE("No roman font installed\n");
2942 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2943 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2944 ret->font_desc.can_use_bitmap = can_use_bitmap;
2945 calc_hash(&ret->font_desc);
2946 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2947 hflist->hfont = hfont;
2948 list_add_head(&ret->hfontlist, &hflist->entry);
2951 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2952 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2953 original value lfCharSet. Note this is a special case for
2954 Symbol and doesn't happen at least for "Wingdings*" */
2956 if(!strcmpiW(lf.lfFaceName, SymbolW))
2957 lf.lfCharSet = SYMBOL_CHARSET;
2959 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2960 switch(lf.lfCharSet) {
2961 case DEFAULT_CHARSET:
2962 csi.fs.fsCsb[0] = 0;
2965 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2966 csi.fs.fsCsb[0] = 0;
2972 if(lf.lfFaceName[0] != '\0') {
2974 SYSTEM_LINKS *font_link;
2975 CHILD_FONT *font_link_entry;
2977 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2980 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2981 debugstr_w(psub->to.name));
2982 strcpyW(lf.lfFaceName, psub->to.name);
2985 /* We want a match on name and charset or just name if
2986 charset was DEFAULT_CHARSET. If the latter then
2987 we fixup the returned charset later in get_nearest_charset
2988 where we'll either use the charset of the current ansi codepage
2989 or if that's unavailable the first charset that the font supports.
2991 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2992 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2993 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2994 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2995 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2996 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2997 if(face->scalable || can_use_bitmap)
3004 * Try check the SystemLink list first for a replacement font.
3005 * We may find good replacements there.
3007 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3009 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
3011 TRACE("found entry in system list\n");
3012 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3014 face = font_link_entry->face;
3015 family = face->family;
3016 if(csi.fs.fsCsb[0] &
3017 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3019 if(face->scalable || can_use_bitmap)
3027 /* If requested charset was DEFAULT_CHARSET then try using charset
3028 corresponding to the current ansi codepage */
3029 if(!csi.fs.fsCsb[0]) {
3031 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3032 FIXME("TCI failed on codepage %d\n", acp);
3033 csi.fs.fsCsb[0] = 0;
3035 lf.lfCharSet = csi.ciCharset;
3038 /* Face families are in the top 4 bits of lfPitchAndFamily,
3039 so mask with 0xF0 before testing */
3041 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3042 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3043 strcpyW(lf.lfFaceName, defFixed);
3044 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3045 strcpyW(lf.lfFaceName, defSerif);
3046 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3047 strcpyW(lf.lfFaceName, defSans);
3049 strcpyW(lf.lfFaceName, defSans);
3050 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3051 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3052 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3053 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3054 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3055 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3056 if(face->scalable || can_use_bitmap)
3062 last_resort_family = NULL;
3063 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3064 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3065 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3066 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3067 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3070 if(can_use_bitmap && !last_resort_family)
3071 last_resort_family = family;
3076 if(last_resort_family) {
3077 family = last_resort_family;
3078 csi.fs.fsCsb[0] = 0;
3082 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3083 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3084 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3085 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3086 if(face->scalable) {
3087 csi.fs.fsCsb[0] = 0;
3088 WARN("just using first face for now\n");
3091 if(can_use_bitmap && !last_resort_family)
3092 last_resort_family = family;
3095 if(!last_resort_family) {
3096 FIXME("can't find a single appropriate font - bailing\n");
3101 WARN("could only find a bitmap font - this will probably look awful!\n");
3102 family = last_resort_family;
3103 csi.fs.fsCsb[0] = 0;
3106 it = lf.lfItalic ? 1 : 0;
3107 bd = lf.lfWeight > 550 ? 1 : 0;
3109 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3110 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3112 face = best = best_bitmap = NULL;
3113 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3115 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3117 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3118 if(!best || new_score <= score)
3120 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3121 face->Italic, face->Bold, it, bd);
3124 if(best->scalable && score == 0) break;
3128 newdiff = height - (signed int)(best->size.height);
3130 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3131 if(!best_bitmap || new_score < score ||
3132 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3134 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3137 if(score == 0 && diff == 0) break;
3144 face = best->scalable ? best : best_bitmap;
3145 ret->fake_italic = (it && !face->Italic);
3146 ret->fake_bold = (bd && !face->Bold);
3148 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
3150 if(csi.fs.fsCsb[0]) {
3151 ret->charset = lf.lfCharSet;
3152 ret->codepage = csi.ciACP;
3155 ret->charset = get_nearest_charset(face, &ret->codepage);
3157 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3158 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3163 ret->aveWidth = abs(lf.lfWidth);
3165 if(!face->scalable) {
3166 ret->ppem = face->size.height;
3167 if (height != 0) ret->ppem += diff;
3169 width = face->size.x_ppem >> 6;
3170 height = face->size.y_ppem >> 6;
3172 ret->ft_face = OpenFontFace(ret, face, width, height);
3180 ret->ntmFlags = face->ntmFlags;
3182 if (ret->charset == SYMBOL_CHARSET &&
3183 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3186 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3190 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3193 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3194 ret->name = strdupW(family->FamilyName);
3195 ret->underline = lf.lfUnderline ? 0xff : 0;
3196 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3197 create_child_font_list(ret);
3199 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3201 list_add_head(&gdi_font_list, &ret->entry);
3205 static void dump_gdi_font_list(void)
3208 struct list *elem_ptr;
3210 TRACE("---------- gdiFont Cache ----------\n");
3211 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3212 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3213 TRACE("gdiFont=%p %s %d\n",
3214 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3217 TRACE("---------- Unused gdiFont Cache ----------\n");
3218 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3219 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3220 TRACE("gdiFont=%p %s %d\n",
3221 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3225 /*************************************************************
3226 * WineEngDestroyFontInstance
3228 * free the gdiFont associated with this handle
3231 BOOL WineEngDestroyFontInstance(HFONT handle)
3236 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3239 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3241 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3242 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3243 if(hflist->hfont == handle)
3245 TRACE("removing child font %p from child list\n", gdiFont);
3246 list_remove(&gdiFont->entry);
3251 TRACE("destroying hfont=%p\n", handle);
3253 dump_gdi_font_list();
3255 font_elem_ptr = list_head(&gdi_font_list);
3256 while(font_elem_ptr) {
3257 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3258 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3260 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3261 while(hfontlist_elem_ptr) {
3262 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3263 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3264 if(hflist->hfont == handle) {
3265 list_remove(&hflist->entry);
3266 HeapFree(GetProcessHeap(), 0, hflist);
3270 if(list_empty(&gdiFont->hfontlist)) {
3271 TRACE("Moving to Unused list\n");
3272 list_remove(&gdiFont->entry);
3273 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3278 font_elem_ptr = list_head(&unused_gdi_font_list);
3279 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3280 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3281 while(font_elem_ptr) {
3282 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3283 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3284 TRACE("freeing %p\n", gdiFont);
3285 list_remove(&gdiFont->entry);
3291 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3292 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3297 if (face->cached_enum_data)
3300 memcpy(pelf, &face->cached_enum_data->elf, sizeof(ENUMLOGFONTEXW));
3301 memcpy(pntm, &face->cached_enum_data->ntm, sizeof(NEWTEXTMETRICEXW));
3302 *ptype = face->cached_enum_data->type;
3306 font = alloc_font();
3308 if(face->scalable) {
3312 height = face->size.y_ppem >> 6;
3313 width = face->size.x_ppem >> 6;
3316 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3322 font->name = strdupW(face->family->FamilyName);
3323 font->ntmFlags = face->ntmFlags;
3325 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3327 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3329 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3331 lstrcpynW(pelf->elfLogFont.lfFaceName,
3332 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3334 lstrcpynW(pelf->elfFullName,
3335 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3337 lstrcpynW(pelf->elfStyle,
3338 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3343 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3345 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3347 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3348 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3349 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3352 pntm->ntmTm.ntmFlags = face->ntmFlags;
3353 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3354 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3355 memcpy(&pntm->ntmFontSig, &face->fs, sizeof(FONTSIGNATURE));
3357 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3359 pelf->elfLogFont.lfEscapement = 0;
3360 pelf->elfLogFont.lfOrientation = 0;
3361 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3362 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3363 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3364 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3365 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3366 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3367 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3368 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3369 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3370 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3371 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3374 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3375 *ptype |= TRUETYPE_FONTTYPE;
3376 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3377 *ptype |= DEVICE_FONTTYPE;
3378 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3379 *ptype |= RASTER_FONTTYPE;
3381 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3382 if (face->cached_enum_data)
3384 memcpy(&face->cached_enum_data->elf, pelf, sizeof(ENUMLOGFONTEXW));
3385 memcpy(&face->cached_enum_data->ntm, pntm, sizeof(NEWTEXTMETRICEXW));
3386 face->cached_enum_data->type = *ptype;
3392 /*************************************************************
3396 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3400 struct list *family_elem_ptr, *face_elem_ptr;
3402 NEWTEXTMETRICEXW ntm;
3403 DWORD type, ret = 1;
3411 lf.lfCharSet = DEFAULT_CHARSET;
3412 lf.lfPitchAndFamily = 0;
3413 lf.lfFaceName[0] = 0;
3417 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3419 if(plf->lfFaceName[0]) {
3421 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3424 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3425 debugstr_w(psub->to.name));
3426 memcpy(&lf, plf, sizeof(lf));
3427 strcpyW(lf.lfFaceName, psub->to.name);
3431 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3432 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3433 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3434 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3435 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3436 GetEnumStructs(face, &elf, &ntm, &type);
3437 for(i = 0; i < 32; i++) {
3438 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3439 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3440 strcpyW(elf.elfScript, OEM_DOSW);
3441 i = 32; /* break out of loop */
3442 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3445 fs.fsCsb[0] = 1L << i;
3447 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3449 csi.ciCharset = DEFAULT_CHARSET;
3450 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3451 if(csi.ciCharset != DEFAULT_CHARSET) {
3452 elf.elfLogFont.lfCharSet =
3453 ntm.ntmTm.tmCharSet = csi.ciCharset;
3455 strcpyW(elf.elfScript, ElfScriptsW[i]);
3457 FIXME("Unknown elfscript for bit %d\n", i);
3460 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3461 debugstr_w(elf.elfLogFont.lfFaceName),
3462 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3463 csi.ciCharset, type, debugstr_w(elf.elfScript),
3464 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3465 ntm.ntmTm.ntmFlags);
3466 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3473 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3474 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3475 face_elem_ptr = list_head(&family->faces);
3476 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3477 GetEnumStructs(face, &elf, &ntm, &type);
3478 for(i = 0; i < 32; i++) {
3479 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3480 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3481 strcpyW(elf.elfScript, OEM_DOSW);
3482 i = 32; /* break out of loop */
3483 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3486 fs.fsCsb[0] = 1L << i;
3488 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3490 csi.ciCharset = DEFAULT_CHARSET;
3491 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3492 if(csi.ciCharset != DEFAULT_CHARSET) {
3493 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3496 strcpyW(elf.elfScript, ElfScriptsW[i]);
3498 FIXME("Unknown elfscript for bit %d\n", i);
3501 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3502 debugstr_w(elf.elfLogFont.lfFaceName),
3503 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3504 csi.ciCharset, type, debugstr_w(elf.elfScript),
3505 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3506 ntm.ntmTm.ntmFlags);
3507 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3516 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3518 pt->x.value = vec->x >> 6;
3519 pt->x.fract = (vec->x & 0x3f) << 10;
3520 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3521 pt->y.value = vec->y >> 6;
3522 pt->y.fract = (vec->y & 0x3f) << 10;
3523 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3527 /***************************************************
3528 * According to the MSDN documentation on WideCharToMultiByte,
3529 * certain codepages cannot set the default_used parameter.
3530 * This returns TRUE if the codepage can set that parameter, false else
3531 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3533 static BOOL codepage_sets_default_used(UINT codepage)
3546 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3548 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3549 WCHAR wc = (WCHAR)glyph;
3551 BOOL *default_used_pointer;
3554 default_used_pointer = NULL;
3555 default_used = FALSE;
3556 if (codepage_sets_default_used(font->codepage))
3557 default_used_pointer = &default_used;
3558 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3561 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3562 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3566 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3567 glyph = glyph + 0xf000;
3568 return pFT_Get_Char_Index(font->ft_face, glyph);
3571 /*************************************************************
3572 * WineEngGetGlyphIndices
3574 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3576 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3577 LPWORD pgi, DWORD flags)
3580 WCHAR default_char = 0;
3583 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3585 for(i = 0; i < count; i++)
3587 pgi[i] = get_glyph_index(font, lpstr[i]);
3592 WineEngGetTextMetrics(font, &textm);
3593 default_char = textm.tmDefaultChar;
3595 pgi[i] = default_char;
3601 /*************************************************************
3602 * WineEngGetGlyphOutline
3604 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3605 * except that the first parameter is the HWINEENGFONT of the font in
3606 * question rather than an HDC.
3609 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3610 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3613 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3614 FT_Face ft_face = incoming_font->ft_face;
3615 GdiFont *font = incoming_font;
3616 FT_UInt glyph_index;
3617 DWORD width, height, pitch, needed = 0;
3618 FT_Bitmap ft_bitmap;
3620 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
3622 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3623 float widthRatio = 1.0, heightRatio = 1.0;
3624 FT_Matrix transMat = identityMat;
3625 BOOL needsTransform = FALSE;
3628 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3629 buflen, buf, lpmat);
3631 if(format & GGO_GLYPH_INDEX) {
3632 glyph_index = glyph;
3633 format &= ~GGO_GLYPH_INDEX;
3635 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3636 ft_face = font->ft_face;
3639 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3640 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3641 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3642 font->gmsize * sizeof(GM*));
3644 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3645 *lpgm = FONT_GM(font,glyph_index)->gm;
3646 return 1; /* FIXME */
3650 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3651 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3653 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
3654 load_flags |= FT_LOAD_NO_BITMAP;
3656 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3659 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3663 /* Scaling factor */
3664 if (font->scale_x != 0.0)
3666 widthRatio = font->scale_x;
3667 heightRatio = font->scale_y;
3670 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3671 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3673 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3675 bbx = (right - left) >> 6;
3677 /* Scaling transform */
3678 if(font->aveWidth) {
3680 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3683 scaleMat.yy = FT_FixedFromFloat(heightRatio);
3685 pFT_Matrix_Multiply(&scaleMat, &transMat);
3686 needsTransform = TRUE;
3689 /* Slant transform */
3690 if (font->fake_italic) {
3693 slantMat.xx = (1 << 16);
3694 slantMat.xy = ((1 << 16) >> 2);
3696 slantMat.yy = (1 << 16);
3697 pFT_Matrix_Multiply(&slantMat, &transMat);
3698 needsTransform = TRUE;
3701 /* Rotation transform */
3702 if(font->orientation) {
3703 FT_Matrix rotationMat;
3705 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3706 pFT_Vector_Unit(&vecAngle, angle);
3707 rotationMat.xx = vecAngle.x;
3708 rotationMat.xy = -vecAngle.y;
3709 rotationMat.yx = -rotationMat.xy;
3710 rotationMat.yy = rotationMat.xx;
3712 pFT_Matrix_Multiply(&rotationMat, &transMat);
3713 needsTransform = TRUE;
3716 /* Extra transformation specified by caller */
3719 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3720 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3721 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3722 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3723 pFT_Matrix_Multiply(&extraMat, &transMat);
3724 needsTransform = TRUE;
3727 if(!needsTransform) {
3728 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3729 bottom = (ft_face->glyph->metrics.horiBearingY -
3730 ft_face->glyph->metrics.height) & -64;
3731 lpgm->gmCellIncX = adv;
3732 lpgm->gmCellIncY = 0;
3736 for(xc = 0; xc < 2; xc++) {
3737 for(yc = 0; yc < 2; yc++) {
3738 vec.x = (ft_face->glyph->metrics.horiBearingX +
3739 xc * ft_face->glyph->metrics.width);
3740 vec.y = ft_face->glyph->metrics.horiBearingY -
3741 yc * ft_face->glyph->metrics.height;
3742 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3743 pFT_Vector_Transform(&vec, &transMat);
3744 if(xc == 0 && yc == 0) {
3745 left = right = vec.x;
3746 top = bottom = vec.y;
3748 if(vec.x < left) left = vec.x;
3749 else if(vec.x > right) right = vec.x;
3750 if(vec.y < bottom) bottom = vec.y;
3751 else if(vec.y > top) top = vec.y;
3756 right = (right + 63) & -64;
3757 bottom = bottom & -64;
3758 top = (top + 63) & -64;
3760 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3761 vec.x = ft_face->glyph->metrics.horiAdvance;
3763 pFT_Vector_Transform(&vec, &transMat);
3764 lpgm->gmCellIncX = (vec.x+63) >> 6;
3765 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3767 lpgm->gmBlackBoxX = (right - left) >> 6;
3768 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3769 lpgm->gmptGlyphOrigin.x = left >> 6;
3770 lpgm->gmptGlyphOrigin.y = top >> 6;
3772 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
3774 FONT_GM(font,glyph_index)->gm = *lpgm;
3775 FONT_GM(font,glyph_index)->adv = adv;
3776 FONT_GM(font,glyph_index)->lsb = lsb;
3777 FONT_GM(font,glyph_index)->bbx = bbx;
3778 FONT_GM(font,glyph_index)->init = TRUE;
3781 if(format == GGO_METRICS)
3782 return 1; /* FIXME */
3784 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
3785 TRACE("loaded a bitmap\n");
3791 width = lpgm->gmBlackBoxX;
3792 height = lpgm->gmBlackBoxY;
3793 pitch = ((width + 31) >> 5) << 2;
3794 needed = pitch * height;
3796 if(!buf || !buflen) break;
3798 switch(ft_face->glyph->format) {
3799 case ft_glyph_format_bitmap:
3801 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3802 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3803 INT h = ft_face->glyph->bitmap.rows;
3805 memcpy(dst, src, w);
3806 src += ft_face->glyph->bitmap.pitch;
3812 case ft_glyph_format_outline:
3813 ft_bitmap.width = width;
3814 ft_bitmap.rows = height;
3815 ft_bitmap.pitch = pitch;
3816 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3817 ft_bitmap.buffer = buf;
3819 if(needsTransform) {
3820 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3823 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3825 /* Note: FreeType will only set 'black' bits for us. */
3826 memset(buf, 0, needed);
3827 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3831 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3836 case GGO_GRAY2_BITMAP:
3837 case GGO_GRAY4_BITMAP:
3838 case GGO_GRAY8_BITMAP:
3839 case WINE_GGO_GRAY16_BITMAP:
3841 unsigned int mult, row, col;
3844 width = lpgm->gmBlackBoxX;
3845 height = lpgm->gmBlackBoxY;
3846 pitch = (width + 3) / 4 * 4;
3847 needed = pitch * height;
3849 if(!buf || !buflen) break;
3851 switch(ft_face->glyph->format) {
3852 case ft_glyph_format_bitmap:
3854 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3855 INT h = ft_face->glyph->bitmap.rows;
3858 for(x = 0; x < pitch; x++)
3859 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3860 src += ft_face->glyph->bitmap.pitch;
3865 case ft_glyph_format_outline:
3867 ft_bitmap.width = width;
3868 ft_bitmap.rows = height;
3869 ft_bitmap.pitch = pitch;
3870 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3871 ft_bitmap.buffer = buf;
3874 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3876 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3878 memset(ft_bitmap.buffer, 0, buflen);
3880 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3882 if(format == GGO_GRAY2_BITMAP)
3884 else if(format == GGO_GRAY4_BITMAP)
3886 else if(format == GGO_GRAY8_BITMAP)
3888 else /* format == WINE_GGO_GRAY16_BITMAP */
3894 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3899 for(row = 0; row < height; row++) {
3901 for(col = 0; col < width; col++, ptr++) {
3902 *ptr = (((int)*ptr) * mult + 128) / 256;
3911 int contour, point = 0, first_pt;
3912 FT_Outline *outline = &ft_face->glyph->outline;
3913 TTPOLYGONHEADER *pph;
3915 DWORD pph_start, cpfx, type;
3917 if(buflen == 0) buf = NULL;
3919 if (needsTransform && buf) {
3920 pFT_Outline_Transform(outline, &transMat);
3923 for(contour = 0; contour < outline->n_contours; contour++) {
3925 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3928 pph->dwType = TT_POLYGON_TYPE;
3929 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3931 needed += sizeof(*pph);
3933 while(point <= outline->contours[contour]) {
3934 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3935 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3936 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3940 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3943 } while(point <= outline->contours[contour] &&
3944 (outline->tags[point] & FT_Curve_Tag_On) ==
3945 (outline->tags[point-1] & FT_Curve_Tag_On));
3946 /* At the end of a contour Windows adds the start point, but
3948 if(point > outline->contours[contour] &&
3949 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3951 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3953 } else if(point <= outline->contours[contour] &&
3954 outline->tags[point] & FT_Curve_Tag_On) {
3955 /* add closing pt for bezier */
3957 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3965 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3968 pph->cb = needed - pph_start;
3974 /* Convert the quadratic Beziers to cubic Beziers.
3975 The parametric eqn for a cubic Bezier is, from PLRM:
3976 r(t) = at^3 + bt^2 + ct + r0
3977 with the control points:
3982 A quadratic Beizer has the form:
3983 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3985 So equating powers of t leads to:
3986 r1 = 2/3 p1 + 1/3 p0
3987 r2 = 2/3 p1 + 1/3 p2
3988 and of course r0 = p0, r3 = p2
3991 int contour, point = 0, first_pt;
3992 FT_Outline *outline = &ft_face->glyph->outline;
3993 TTPOLYGONHEADER *pph;
3995 DWORD pph_start, cpfx, type;
3996 FT_Vector cubic_control[4];
3997 if(buflen == 0) buf = NULL;
3999 if (needsTransform && buf) {
4000 pFT_Outline_Transform(outline, &transMat);
4003 for(contour = 0; contour < outline->n_contours; contour++) {
4005 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4008 pph->dwType = TT_POLYGON_TYPE;
4009 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4011 needed += sizeof(*pph);
4013 while(point <= outline->contours[contour]) {
4014 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4015 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4016 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4019 if(type == TT_PRIM_LINE) {
4021 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4025 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4028 /* FIXME: Possible optimization in endpoint calculation
4029 if there are two consecutive curves */
4030 cubic_control[0] = outline->points[point-1];
4031 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4032 cubic_control[0].x += outline->points[point].x + 1;
4033 cubic_control[0].y += outline->points[point].y + 1;
4034 cubic_control[0].x >>= 1;
4035 cubic_control[0].y >>= 1;
4037 if(point+1 > outline->contours[contour])
4038 cubic_control[3] = outline->points[first_pt];
4040 cubic_control[3] = outline->points[point+1];
4041 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4042 cubic_control[3].x += outline->points[point].x + 1;
4043 cubic_control[3].y += outline->points[point].y + 1;
4044 cubic_control[3].x >>= 1;
4045 cubic_control[3].y >>= 1;
4048 /* r1 = 1/3 p0 + 2/3 p1
4049 r2 = 1/3 p2 + 2/3 p1 */
4050 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4051 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4052 cubic_control[2] = cubic_control[1];
4053 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4054 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4055 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4056 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4058 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4059 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4060 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4065 } while(point <= outline->contours[contour] &&
4066 (outline->tags[point] & FT_Curve_Tag_On) ==
4067 (outline->tags[point-1] & FT_Curve_Tag_On));
4068 /* At the end of a contour Windows adds the start point,
4069 but only for Beziers and we've already done that.
4071 if(point <= outline->contours[contour] &&
4072 outline->tags[point] & FT_Curve_Tag_On) {
4073 /* This is the closing pt of a bezier, but we've already
4074 added it, so just inc point and carry on */
4081 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4084 pph->cb = needed - pph_start;
4090 FIXME("Unsupported format %d\n", format);
4096 static BOOL get_bitmap_text_metrics(GdiFont *font)
4098 FT_Face ft_face = font->ft_face;
4099 #ifdef HAVE_FREETYPE_FTWINFNT_H
4100 FT_WinFNT_HeaderRec winfnt_header;
4102 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4103 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4104 font->potm->otmSize = size;
4106 #define TM font->potm->otmTextMetrics
4107 #ifdef HAVE_FREETYPE_FTWINFNT_H
4108 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4110 TM.tmHeight = winfnt_header.pixel_height;
4111 TM.tmAscent = winfnt_header.ascent;
4112 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4113 TM.tmInternalLeading = winfnt_header.internal_leading;
4114 TM.tmExternalLeading = winfnt_header.external_leading;
4115 TM.tmAveCharWidth = winfnt_header.avg_width;
4116 TM.tmMaxCharWidth = winfnt_header.max_width;
4117 TM.tmWeight = winfnt_header.weight;
4119 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4120 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4121 TM.tmFirstChar = winfnt_header.first_char;
4122 TM.tmLastChar = winfnt_header.last_char;
4123 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4124 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4125 TM.tmItalic = winfnt_header.italic;
4126 TM.tmUnderlined = font->underline;
4127 TM.tmStruckOut = font->strikeout;
4128 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4129 TM.tmCharSet = winfnt_header.charset;
4134 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4135 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4136 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4137 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4138 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4139 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4140 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4141 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4143 TM.tmDigitizedAspectX = 96; /* FIXME */
4144 TM.tmDigitizedAspectY = 96; /* FIXME */
4146 TM.tmLastChar = 255;
4147 TM.tmDefaultChar = 32;
4148 TM.tmBreakChar = 32;
4149 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4150 TM.tmUnderlined = font->underline;
4151 TM.tmStruckOut = font->strikeout;
4152 /* NB inverted meaning of TMPF_FIXED_PITCH */
4153 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4154 TM.tmCharSet = font->charset;
4162 static void scale_font_metrics(GdiFont *font, LPTEXTMETRICW ptm)
4164 if (font->scale_x == 0.0)
4166 if (FT_IS_SCALABLE(font->ft_face) || !font->ppem)
4167 font->scale_y = 1.0;
4170 font->scale_y = (float)font->ppem * font->font_desc.matrix.eM22;
4171 font->scale_y /= (float)font->potm->otmTextMetrics.tmHeight;
4176 font->scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4177 font->scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4180 font->scale_x = font->scale_y;
4182 TRACE("font scale x: %f y: %f\n", font->scale_x, font->scale_y);
4184 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4185 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4186 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4187 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4188 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4190 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * font->scale_x;
4191 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * font->scale_x;
4194 /*************************************************************
4195 * WineEngGetTextMetrics
4198 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4201 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4202 if(!get_bitmap_text_metrics(font))
4205 if(!font->potm) return FALSE;
4206 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
4207 scale_font_metrics(font, ptm);
4213 /*************************************************************
4214 * WineEngGetOutlineTextMetrics
4217 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4218 OUTLINETEXTMETRICW *potm)
4220 FT_Face ft_face = font->ft_face;
4221 UINT needed, lenfam, lensty, ret;
4223 TT_HoriHeader *pHori;
4224 TT_Postscript *pPost;
4225 FT_Fixed x_scale, y_scale;
4226 WCHAR *family_nameW, *style_nameW;
4227 static const WCHAR spaceW[] = {' ', '\0'};
4229 INT ascent, descent;
4231 TRACE("font=%p\n", font);
4233 if(!FT_IS_SCALABLE(ft_face))
4237 if(cbSize >= font->potm->otmSize)
4239 memcpy(potm, font->potm, font->potm->otmSize);
4240 scale_font_metrics(font, &potm->otmTextMetrics);
4242 return font->potm->otmSize;
4246 needed = sizeof(*potm);
4248 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4249 family_nameW = strdupW(font->name);
4251 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4253 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4254 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4255 style_nameW, lensty/sizeof(WCHAR));
4257 /* These names should be read from the TT name table */
4259 /* length of otmpFamilyName */
4262 /* length of otmpFaceName */
4263 if(!strcasecmp(ft_face->style_name, "regular")) {
4264 needed += lenfam; /* just the family name */
4266 needed += lenfam + lensty; /* family + " " + style */
4269 /* length of otmpStyleName */
4272 /* length of otmpFullName */
4273 needed += lenfam + lensty;
4276 x_scale = ft_face->size->metrics.x_scale;
4277 y_scale = ft_face->size->metrics.y_scale;
4279 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4281 FIXME("Can't find OS/2 table - not TT font?\n");
4286 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4288 FIXME("Can't find HHEA table - not TT font?\n");
4293 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4295 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",
4296 pOS2->usWinAscent, pOS2->usWinDescent,
4297 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4298 ft_face->ascender, ft_face->descender, ft_face->height,
4299 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4300 ft_face->bbox.yMax, ft_face->bbox.yMin);
4302 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4303 font->potm->otmSize = needed;
4305 #define TM font->potm->otmTextMetrics
4307 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4308 ascent = pHori->Ascender;
4309 descent = -pHori->Descender;
4311 ascent = pOS2->usWinAscent;
4312 descent = pOS2->usWinDescent;
4316 TM.tmAscent = font->yMax;
4317 TM.tmDescent = -font->yMin;
4318 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4320 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4321 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4322 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4323 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4326 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4329 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4331 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4332 ((ascent + descent) -
4333 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4335 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4336 if (TM.tmAveCharWidth == 0) {
4337 TM.tmAveCharWidth = 1;
4339 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4340 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4342 TM.tmDigitizedAspectX = 300;
4343 TM.tmDigitizedAspectY = 300;
4344 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4345 * symbol range to 0 - f0ff
4347 if (font->charset == SYMBOL_CHARSET)
4350 TM.tmFirstChar = pOS2->usFirstCharIndex;
4351 TM.tmLastChar = pOS2->usLastCharIndex;
4352 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4353 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4354 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4355 TM.tmUnderlined = font->underline;
4356 TM.tmStruckOut = font->strikeout;
4358 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4359 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4360 (pOS2->version == 0xFFFFU ||
4361 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4362 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4364 TM.tmPitchAndFamily = 0;
4366 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4367 case PAN_FAMILY_SCRIPT:
4368 TM.tmPitchAndFamily |= FF_SCRIPT;
4370 case PAN_FAMILY_DECORATIVE:
4371 case PAN_FAMILY_PICTORIAL:
4372 TM.tmPitchAndFamily |= FF_DECORATIVE;
4374 case PAN_FAMILY_TEXT_DISPLAY:
4375 if(TM.tmPitchAndFamily == 0) /* fixed */
4376 TM.tmPitchAndFamily = FF_MODERN;
4378 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4379 case PAN_SERIF_NORMAL_SANS:
4380 case PAN_SERIF_OBTUSE_SANS:
4381 case PAN_SERIF_PERP_SANS:
4382 TM.tmPitchAndFamily |= FF_SWISS;
4385 TM.tmPitchAndFamily |= FF_ROMAN;
4390 TM.tmPitchAndFamily |= FF_DONTCARE;
4393 if(FT_IS_SCALABLE(ft_face))
4394 TM.tmPitchAndFamily |= TMPF_VECTOR;
4396 if(FT_IS_SFNT(ft_face))
4398 if (font->ntmFlags & NTM_PS_OPENTYPE)
4399 TM.tmPitchAndFamily |= TMPF_DEVICE;
4401 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4404 TM.tmCharSet = font->charset;
4407 font->potm->otmFiller = 0;
4408 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4409 font->potm->otmfsSelection = pOS2->fsSelection;
4410 font->potm->otmfsType = pOS2->fsType;
4411 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4412 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4413 font->potm->otmItalicAngle = 0; /* POST table */
4414 font->potm->otmEMSquare = ft_face->units_per_EM;
4415 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4416 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4417 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4418 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4419 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4420 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4421 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4422 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4423 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4424 font->potm->otmMacAscent = 0; /* where do these come from ? */
4425 font->potm->otmMacDescent = 0;
4426 font->potm->otmMacLineGap = 0;
4427 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4428 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4429 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4430 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4431 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4432 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4433 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4434 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4435 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4436 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4437 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4439 font->potm->otmsUnderscoreSize = 0;
4440 font->potm->otmsUnderscorePosition = 0;
4442 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4443 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4446 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4447 cp = (char*)font->potm + sizeof(*font->potm);
4448 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4449 strcpyW((WCHAR*)cp, family_nameW);
4451 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4452 strcpyW((WCHAR*)cp, style_nameW);
4454 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4455 strcpyW((WCHAR*)cp, family_nameW);
4456 if(strcasecmp(ft_face->style_name, "regular")) {
4457 strcatW((WCHAR*)cp, spaceW);
4458 strcatW((WCHAR*)cp, style_nameW);
4459 cp += lenfam + lensty;
4462 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4463 strcpyW((WCHAR*)cp, family_nameW);
4464 strcatW((WCHAR*)cp, spaceW);
4465 strcatW((WCHAR*)cp, style_nameW);
4468 if(potm && needed <= cbSize)
4470 memcpy(potm, font->potm, font->potm->otmSize);
4471 scale_font_metrics(font, &potm->otmTextMetrics);
4475 HeapFree(GetProcessHeap(), 0, style_nameW);
4476 HeapFree(GetProcessHeap(), 0, family_nameW);
4481 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4483 HFONTLIST *hfontlist;
4484 child->font = alloc_font();
4485 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
4486 if(!child->font->ft_face)
4488 free_font(child->font);
4493 child->font->ntmFlags = child->face->ntmFlags;
4494 child->font->orientation = font->orientation;
4495 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4496 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4497 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4498 child->font->base_font = font;
4499 list_add_head(&child_font_list, &child->font->entry);
4500 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4504 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4507 CHILD_FONT *child_font;
4510 font = font->base_font;
4512 *linked_font = font;
4514 if((*glyph = get_glyph_index(font, c)))
4517 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4519 if(!child_font->font)
4520 if(!load_child_font(font, child_font))
4523 if(!child_font->font->ft_face)
4525 g = get_glyph_index(child_font->font, c);
4529 *linked_font = child_font->font;
4536 /*************************************************************
4537 * WineEngGetCharWidth
4540 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4545 FT_UInt glyph_index;
4546 GdiFont *linked_font;
4548 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4550 for(c = firstChar; c <= lastChar; c++) {
4551 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4552 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4553 &gm, 0, NULL, NULL);
4554 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4559 /*************************************************************
4560 * WineEngGetCharABCWidths
4563 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4568 FT_UInt glyph_index;
4569 GdiFont *linked_font;
4571 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4573 if(!FT_IS_SCALABLE(font->ft_face))
4576 for(c = firstChar; c <= lastChar; c++) {
4577 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4578 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4579 &gm, 0, NULL, NULL);
4580 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4581 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4582 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4583 FONT_GM(linked_font,glyph_index)->bbx;
4588 /*************************************************************
4589 * WineEngGetCharABCWidthsI
4592 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4597 FT_UInt glyph_index;
4598 GdiFont *linked_font;
4600 if(!FT_HAS_HORIZONTAL(font->ft_face))
4603 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4605 for(c = firstChar; c < firstChar+count; c++) {
4606 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4607 &gm, 0, NULL, NULL);
4608 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4609 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4610 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4611 - FONT_GM(linked_font,c)->bbx;
4614 for(c = 0; c < count; c++) {
4615 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4616 &gm, 0, NULL, NULL);
4617 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4618 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4619 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4620 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4626 /*************************************************************
4627 * WineEngGetTextExtentExPoint
4630 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4631 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4637 FT_UInt glyph_index;
4638 GdiFont *linked_font;
4640 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4644 WineEngGetTextMetrics(font, &tm);
4645 size->cy = tm.tmHeight;
4647 for(idx = 0; idx < count; idx++) {
4648 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4649 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4650 &gm, 0, NULL, NULL);
4651 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4653 if (! pnfit || ext <= max_ext) {
4663 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4667 /*************************************************************
4668 * WineEngGetTextExtentExPointI
4671 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
4672 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4679 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
4682 WineEngGetTextMetrics(font, &tm);
4683 size->cy = tm.tmHeight;
4685 for(idx = 0; idx < count; idx++) {
4686 WineEngGetGlyphOutline(font, indices[idx],
4687 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4689 size->cx += FONT_GM(font,indices[idx])->adv;
4691 if (! pnfit || ext <= max_ext) {
4701 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4705 /*************************************************************
4706 * WineEngGetFontData
4709 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4712 FT_Face ft_face = font->ft_face;
4716 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4717 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4718 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4720 if(!FT_IS_SFNT(ft_face))
4728 if(table) { /* MS tags differ in endidness from FT ones */
4729 table = table >> 24 | table << 24 |
4730 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4733 /* make sure value of len is the value freetype says it needs */
4736 FT_ULong needed = 0;
4737 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
4738 if( !err && needed < len) len = needed;
4740 err = load_sfnt_table(ft_face, table, offset, buf, &len);
4743 TRACE("Can't find table %c%c%c%c\n",
4744 /* bytes were reversed */
4745 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4746 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4752 /*************************************************************
4753 * WineEngGetTextFace
4756 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4759 lstrcpynW(str, font->name, count);
4760 return strlenW(font->name);
4762 return strlenW(font->name) + 1;
4765 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4767 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4768 return font->charset;
4771 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4773 GdiFont *font = dc->gdiFont, *linked_font;
4774 struct list *first_hfont;
4777 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4778 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4779 if(font == linked_font)
4780 *new_hfont = dc->hFont;
4783 first_hfont = list_head(&linked_font->hfontlist);
4784 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4790 /* Retrieve a list of supported Unicode ranges for a given font.
4791 * Can be called with NULL gs to calculate the buffer size. Returns
4792 * the number of ranges found.
4794 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4796 DWORD num_ranges = 0;
4798 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4801 FT_ULong char_code, char_code_prev;
4804 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4806 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4807 face->num_glyphs, glyph_code, char_code);
4809 if (!glyph_code) return 0;
4813 gs->ranges[0].wcLow = (USHORT)char_code;
4814 gs->ranges[0].cGlyphs = 0;
4815 gs->cGlyphsSupported = 0;
4821 if (char_code < char_code_prev)
4823 ERR("expected increasing char code from FT_Get_Next_Char\n");
4826 if (char_code - char_code_prev > 1)
4831 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4832 gs->ranges[num_ranges - 1].cGlyphs = 1;
4833 gs->cGlyphsSupported++;
4838 gs->ranges[num_ranges - 1].cGlyphs++;
4839 gs->cGlyphsSupported++;
4841 char_code_prev = char_code;
4842 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4846 FIXME("encoding %u not supported\n", face->charmap->encoding);
4851 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
4854 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
4856 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4859 glyphset->cbThis = size;
4860 glyphset->cRanges = num_ranges;
4865 /*************************************************************
4868 BOOL WineEngFontIsLinked(GdiFont *font)
4870 return !list_empty(&font->child_fonts);
4873 static BOOL is_hinting_enabled(void)
4875 /* Use the >= 2.2.0 function if available */
4876 if(pFT_Get_TrueType_Engine_Type)
4878 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4879 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4881 #ifdef FT_DRIVER_HAS_HINTER
4886 /* otherwise if we've been compiled with < 2.2.0 headers
4887 use the internal macro */
4888 mod = pFT_Get_Module(library, "truetype");
4889 if(mod && FT_DRIVER_HAS_HINTER(mod))
4897 /*************************************************************************
4898 * GetRasterizerCaps (GDI32.@)
4900 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4902 static int hinting = -1;
4906 hinting = is_hinting_enabled();
4907 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4910 lprs->nSize = sizeof(RASTERIZER_STATUS);
4911 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4912 lprs->nLanguageID = 0;
4916 /*************************************************************************
4917 * Kerning support for TrueType fonts
4919 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4921 struct TT_kern_table
4927 struct TT_kern_subtable
4936 USHORT horizontal : 1;
4938 USHORT cross_stream: 1;
4939 USHORT override : 1;
4940 USHORT reserved1 : 4;
4946 struct TT_format0_kern_subtable
4950 USHORT entrySelector;
4961 static DWORD parse_format0_kern_subtable(GdiFont *font,
4962 const struct TT_format0_kern_subtable *tt_f0_ks,
4963 const USHORT *glyph_to_char,
4964 KERNINGPAIR *kern_pair, DWORD cPairs)
4967 const struct TT_kern_pair *tt_kern_pair;
4969 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4971 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4973 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4974 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4975 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4977 if (!kern_pair || !cPairs)
4980 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4982 nPairs = min(nPairs, cPairs);
4984 for (i = 0; i < nPairs; i++)
4986 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4987 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4988 /* this algorithm appears to better match what Windows does */
4989 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4990 if (kern_pair->iKernAmount < 0)
4992 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4993 kern_pair->iKernAmount -= font->ppem;
4995 else if (kern_pair->iKernAmount > 0)
4997 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4998 kern_pair->iKernAmount += font->ppem;
5000 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5002 TRACE("left %u right %u value %d\n",
5003 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5007 TRACE("copied %u entries\n", nPairs);
5011 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5015 const struct TT_kern_table *tt_kern_table;
5016 const struct TT_kern_subtable *tt_kern_subtable;
5018 USHORT *glyph_to_char;
5020 if (font->total_kern_pairs != (DWORD)-1)
5022 if (cPairs && kern_pair)
5024 cPairs = min(cPairs, font->total_kern_pairs);
5025 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5028 return font->total_kern_pairs;
5031 font->total_kern_pairs = 0;
5033 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5035 if (length == GDI_ERROR)
5037 TRACE("no kerning data in the font\n");
5041 buf = HeapAlloc(GetProcessHeap(), 0, length);
5044 WARN("Out of memory\n");
5048 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5050 /* build a glyph index to char code map */
5051 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5054 WARN("Out of memory allocating a glyph index to char code map\n");
5055 HeapFree(GetProcessHeap(), 0, buf);
5059 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5065 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5067 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5068 font->ft_face->num_glyphs, glyph_code, char_code);
5072 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5074 /* FIXME: This doesn't match what Windows does: it does some fancy
5075 * things with duplicate glyph index to char code mappings, while
5076 * we just avoid overriding existing entries.
5078 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5079 glyph_to_char[glyph_code] = (USHORT)char_code;
5081 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5088 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5089 for (n = 0; n <= 65535; n++)
5090 glyph_to_char[n] = (USHORT)n;
5093 tt_kern_table = buf;
5094 nTables = GET_BE_WORD(tt_kern_table->nTables);
5095 TRACE("version %u, nTables %u\n",
5096 GET_BE_WORD(tt_kern_table->version), nTables);
5098 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5100 for (i = 0; i < nTables; i++)
5102 struct TT_kern_subtable tt_kern_subtable_copy;
5104 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5105 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5106 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5108 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5109 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5110 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5112 /* According to the TrueType specification this is the only format
5113 * that will be properly interpreted by Windows and OS/2
5115 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5117 DWORD new_chunk, old_total = font->total_kern_pairs;
5119 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5120 glyph_to_char, NULL, 0);
5121 font->total_kern_pairs += new_chunk;
5123 if (!font->kern_pairs)
5124 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5125 font->total_kern_pairs * sizeof(*font->kern_pairs));
5127 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5128 font->total_kern_pairs * sizeof(*font->kern_pairs));
5130 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5131 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5134 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5136 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5139 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5140 HeapFree(GetProcessHeap(), 0, buf);
5142 if (cPairs && kern_pair)
5144 cPairs = min(cPairs, font->total_kern_pairs);
5145 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5148 return font->total_kern_pairs;
5151 #else /* HAVE_FREETYPE */
5153 /*************************************************************************/
5155 BOOL WineEngInit(void)
5159 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5163 BOOL WineEngDestroyFontInstance(HFONT hfont)
5168 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5173 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5174 LPWORD pgi, DWORD flags)
5179 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5180 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5183 ERR("called but we don't have FreeType\n");
5187 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5189 ERR("called but we don't have FreeType\n");
5193 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5194 OUTLINETEXTMETRICW *potm)
5196 ERR("called but we don't have FreeType\n");
5200 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5203 ERR("called but we don't have FreeType\n");
5207 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5210 ERR("called but we don't have FreeType\n");
5214 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5217 ERR("called but we don't have FreeType\n");
5221 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5222 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5224 ERR("called but we don't have FreeType\n");
5228 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5229 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5231 ERR("called but we don't have FreeType\n");
5235 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5238 ERR("called but we don't have FreeType\n");
5242 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5244 ERR("called but we don't have FreeType\n");
5248 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5254 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5260 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5266 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5269 return DEFAULT_CHARSET;
5272 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5277 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5279 FIXME("(%p, %p): stub\n", font, glyphset);
5283 BOOL WineEngFontIsLinked(GdiFont *font)
5288 /*************************************************************************
5289 * GetRasterizerCaps (GDI32.@)
5291 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5293 lprs->nSize = sizeof(RASTERIZER_STATUS);
5295 lprs->nLanguageID = 0;
5299 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5301 ERR("called but we don't have FreeType\n");
5305 #endif /* HAVE_FREETYPE */