2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
60 #undef GetCurrentThread
63 #undef GetCurrentProcess
76 #endif /* HAVE_CARBON_CARBON_H */
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
93 #ifdef HAVE_FT2BUILD_H
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
105 #ifdef HAVE_FREETYPE_FTSNAMES_H
106 #include <freetype/ftsnames.h>
108 # ifdef HAVE_FREETYPE_FTNAMES_H
109 # include <freetype/ftnames.h>
112 #ifdef HAVE_FREETYPE_TTNAMEID_H
113 #include <freetype/ttnameid.h>
115 #ifdef HAVE_FREETYPE_FTOUTLN_H
116 #include <freetype/ftoutln.h>
118 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
119 #include <freetype/internal/sfnt.h>
121 #ifdef HAVE_FREETYPE_FTTRIGON_H
122 #include <freetype/fttrigon.h>
124 #ifdef HAVE_FREETYPE_FTWINFNT_H
125 #include <freetype/ftwinfnt.h>
127 #ifdef HAVE_FREETYPE_FTMODAPI_H
128 #include <freetype/ftmodapi.h>
131 #ifndef HAVE_FT_TRUETYPEENGINETYPE
134 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
135 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
136 FT_TRUETYPE_ENGINE_TYPE_PATENTED
137 } FT_TrueTypeEngineType;
140 static FT_Library library = 0;
147 static FT_Version_t FT_Version;
148 static DWORD FT_SimpleVersion;
150 static void *ft_handle = NULL;
152 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
153 MAKE_FUNCPTR(FT_Vector_Unit);
154 MAKE_FUNCPTR(FT_Done_Face);
155 MAKE_FUNCPTR(FT_Get_Char_Index);
156 MAKE_FUNCPTR(FT_Get_Module);
157 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
158 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
159 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
160 MAKE_FUNCPTR(FT_Init_FreeType);
161 MAKE_FUNCPTR(FT_Load_Glyph);
162 MAKE_FUNCPTR(FT_Matrix_Multiply);
163 MAKE_FUNCPTR(FT_MulFix);
164 MAKE_FUNCPTR(FT_New_Face);
165 MAKE_FUNCPTR(FT_New_Memory_Face);
166 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
167 MAKE_FUNCPTR(FT_Outline_Transform);
168 MAKE_FUNCPTR(FT_Outline_Translate);
169 MAKE_FUNCPTR(FT_Select_Charmap);
170 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
171 MAKE_FUNCPTR(FT_Vector_Transform);
172 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
173 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
174 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
175 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
176 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
177 #ifdef HAVE_FREETYPE_FTWINFNT_H
178 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
181 #ifdef SONAME_LIBFONTCONFIG
182 #include <fontconfig/fontconfig.h>
183 MAKE_FUNCPTR(FcConfigGetCurrent);
184 MAKE_FUNCPTR(FcFontList);
185 MAKE_FUNCPTR(FcFontSetDestroy);
186 MAKE_FUNCPTR(FcInit);
187 MAKE_FUNCPTR(FcObjectSetAdd);
188 MAKE_FUNCPTR(FcObjectSetCreate);
189 MAKE_FUNCPTR(FcObjectSetDestroy);
190 MAKE_FUNCPTR(FcPatternCreate);
191 MAKE_FUNCPTR(FcPatternDestroy);
192 MAKE_FUNCPTR(FcPatternGetBool);
193 MAKE_FUNCPTR(FcPatternGetString);
198 #ifndef ft_encoding_none
199 #define FT_ENCODING_NONE ft_encoding_none
201 #ifndef ft_encoding_ms_symbol
202 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
204 #ifndef ft_encoding_unicode
205 #define FT_ENCODING_UNICODE ft_encoding_unicode
207 #ifndef ft_encoding_apple_roman
208 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
211 #ifdef WORDS_BIGENDIAN
212 #define GET_BE_WORD(x) (x)
214 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
217 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
224 FT_Short internal_leading;
227 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
228 So to let this compile on older versions of FreeType we'll define the
229 new structure here. */
231 FT_Short height, width;
232 FT_Pos size, x_ppem, y_ppem;
235 typedef struct tagFace {
240 DWORD font_data_size;
245 FONTSIGNATURE fs_links;
246 DWORD ntmFlags; /* Only some bits stored here. Others are computed on the fly */
247 FT_Fixed font_version;
249 Bitmap_Size size; /* set if face is a bitmap */
250 BOOL external; /* TRUE if we should manually add this font to the registry */
251 struct tagFamily *family;
254 typedef struct tagFamily {
256 const WCHAR *FamilyName;
262 INT adv; /* These three hold to widths of the unrotated chars */
280 typedef struct tagHFONTLIST {
294 struct font_mapping *mapping;
305 struct list hfontlist;
310 OUTLINETEXTMETRICW *potm;
312 DWORD total_kern_pairs;
313 KERNINGPAIR *kern_pairs;
316 struct list child_fonts;
322 const WCHAR *font_name;
326 #define GM_BLOCK_SIZE 128
327 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
329 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
330 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
331 #define UNUSED_CACHE_SIZE 10
332 static struct list child_font_list = LIST_INIT(child_font_list);
333 static struct list system_links = LIST_INIT(system_links);
335 static struct list font_subst_list = LIST_INIT(font_subst_list);
337 static struct list font_list = LIST_INIT(font_list);
339 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
340 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
341 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
343 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
345 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
346 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
347 'W','i','n','d','o','w','s','\\',
348 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
349 'F','o','n','t','s','\0'};
351 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
352 'W','i','n','d','o','w','s',' ','N','T','\\',
353 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
354 'F','o','n','t','s','\0'};
356 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
357 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
358 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
359 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
361 static const WCHAR * const SystemFontValues[4] = {
368 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
369 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
371 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
372 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
373 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
374 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
375 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
376 'E','u','r','o','p','e','a','n','\0'};
377 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
378 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
379 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
380 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
381 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
382 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
383 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
384 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
385 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
386 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
387 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
388 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
390 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
400 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
408 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
417 typedef struct tagFontSubst {
433 static struct list mappings_list = LIST_INIT( mappings_list );
435 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
437 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
439 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
441 /****************************************
442 * Notes on .fon files
444 * The fonts System, FixedSys and Terminal are special. There are typically multiple
445 * versions installed for different resolutions and codepages. Windows stores which one to use
446 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
448 * FIXEDFON.FON FixedSys
450 * OEMFONT.FON Terminal
451 * LogPixels Current dpi set by the display control panel applet
452 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
453 * also has a LogPixels value that appears to mirror this)
455 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
456 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
457 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
458 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
459 * so that makes sense.
461 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
462 * to be mapped into the registry on Windows 2000 at least).
465 * ega80woa.fon=ega80850.fon
466 * ega40woa.fon=ega40850.fon
467 * cga80woa.fon=cga80850.fon
468 * cga40woa.fon=cga40850.fon
471 #ifdef HAVE_CARBON_CARBON_H
472 static char *find_cache_dir(void)
476 static char cached_path[MAX_PATH];
477 static const char *wine = "/Wine", *fonts = "/Fonts";
479 if(*cached_path) return cached_path;
481 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
484 WARN("can't create cached data folder\n");
487 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
490 WARN("can't create cached data path\n");
494 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
496 ERR("Could not create full path\n");
500 strcat(cached_path, wine);
502 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
504 WARN("Couldn't mkdir %s\n", cached_path);
508 strcat(cached_path, fonts);
509 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
511 WARN("Couldn't mkdir %s\n", cached_path);
518 /******************************************************************
521 * Extracts individual TrueType font files from a Mac suitcase font
522 * and saves them into the user's caches directory (see
524 * Returns a NULL terminated array of filenames.
526 * We do this because they are apps that try to read ttf files
527 * themselves and they don't like Mac suitcase files.
529 static char **expand_mac_font(const char *path)
536 const char *filename;
540 unsigned int size, max_size;
543 TRACE("path %s\n", path);
545 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
548 WARN("failed to get ref\n");
552 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
555 TRACE("no data fork, so trying resource fork\n");
556 res_ref = FSOpenResFile(&ref, fsRdPerm);
559 TRACE("unable to open resource fork\n");
566 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
569 CloseResFile(res_ref);
573 out_dir = find_cache_dir();
575 filename = strrchr(path, '/');
576 if(!filename) filename = path;
579 /* output filename has the form out_dir/filename_%04x.ttf */
580 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
587 unsigned short *num_faces_ptr, num_faces, face;
590 ResType fond_res = 0x464f4e44; /* 'FOND' */
592 fond = Get1IndResource(fond_res, idx);
594 TRACE("got fond resource %d\n", idx);
597 fam_rec = *(FamRec**)fond;
598 num_faces_ptr = (unsigned short *)(fam_rec + 1);
599 num_faces = GET_BE_WORD(*num_faces_ptr);
601 assoc = (AsscEntry*)(num_faces_ptr + 1);
602 TRACE("num faces %04x\n", num_faces);
603 for(face = 0; face < num_faces; face++, assoc++)
606 ResType sfnt_res = 0x73666e74; /* 'sfnt' */
607 unsigned short size, font_id;
610 size = GET_BE_WORD(assoc->fontSize);
611 font_id = GET_BE_WORD(assoc->fontID);
614 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
618 TRACE("trying to load sfnt id %04x\n", font_id);
619 sfnt = GetResource(sfnt_res, font_id);
622 TRACE("can't get sfnt resource %04x\n", font_id);
626 output = HeapAlloc(GetProcessHeap(), 0, output_len);
631 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
633 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
634 if(fd != -1 || errno == EEXIST)
638 unsigned char *sfnt_data;
641 sfnt_data = *(unsigned char**)sfnt;
642 write(fd, sfnt_data, GetHandleSize(sfnt));
646 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
649 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
651 ret.array[ret.size++] = output;
655 WARN("unable to create %s\n", output);
656 HeapFree(GetProcessHeap(), 0, output);
659 ReleaseResource(sfnt);
662 ReleaseResource(fond);
665 CloseResFile(res_ref);
670 #endif /* HAVE_CARBON_CARBON_H */
672 static inline BOOL is_win9x(void)
674 return GetVersion() & 0x80000000;
677 This function builds an FT_Fixed from a float. It puts the integer part
678 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
679 It fails if the integer part of the float number is greater than SHORT_MAX.
681 static inline FT_Fixed FT_FixedFromFloat(float f)
684 unsigned short fract = (f - value) * 0xFFFF;
685 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
689 This function builds an FT_Fixed from a FIXED. It simply put f.value
690 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
692 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
694 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
698 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
703 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
704 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
706 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
707 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
709 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
711 if(face_name && strcmpiW(face_name, family->FamilyName))
713 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
717 file = strrchr(face->file, '/');
722 if(!strcasecmp(file, file_nameA))
724 HeapFree(GetProcessHeap(), 0, file_nameA);
729 HeapFree(GetProcessHeap(), 0, file_nameA);
733 static Family *find_family_from_name(const WCHAR *name)
737 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
739 if(!strcmpiW(family->FamilyName, name))
746 static void DumpSubstList(void)
750 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
752 if(psub->from.charset != -1 || psub->to.charset != -1)
753 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
754 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
756 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
757 debugstr_w(psub->to.name));
762 static LPWSTR strdupW(LPCWSTR p)
765 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
766 ret = HeapAlloc(GetProcessHeap(), 0, len);
771 static LPSTR strdupA(LPCSTR p)
774 DWORD len = (strlen(p) + 1);
775 ret = HeapAlloc(GetProcessHeap(), 0, len);
780 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
785 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
787 if(!strcmpiW(element->from.name, from_name) &&
788 (element->from.charset == from_charset ||
789 element->from.charset == -1))
796 #define ADD_FONT_SUBST_FORCE 1
798 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
800 FontSubst *from_exist, *to_exist;
802 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
804 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
806 list_remove(&from_exist->entry);
807 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
808 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
809 HeapFree(GetProcessHeap(), 0, from_exist);
815 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
819 HeapFree(GetProcessHeap(), 0, subst->to.name);
820 subst->to.name = strdupW(to_exist->to.name);
823 list_add_tail(subst_list, &subst->entry);
828 HeapFree(GetProcessHeap(), 0, subst->from.name);
829 HeapFree(GetProcessHeap(), 0, subst->to.name);
830 HeapFree(GetProcessHeap(), 0, subst);
834 static void split_subst_info(NameCs *nc, LPSTR str)
836 CHAR *p = strrchr(str, ',');
841 nc->charset = strtol(p+1, NULL, 10);
844 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
845 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
846 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
849 static void LoadSubstList(void)
853 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
857 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
858 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
859 &hkey) == ERROR_SUCCESS) {
861 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
862 &valuelen, &datalen, NULL, NULL);
864 valuelen++; /* returned value doesn't include room for '\0' */
865 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
866 data = HeapAlloc(GetProcessHeap(), 0, datalen);
870 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
871 &dlen) == ERROR_SUCCESS) {
872 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
874 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
875 split_subst_info(&psub->from, value);
876 split_subst_info(&psub->to, data);
878 /* Win 2000 doesn't allow mapping between different charsets
879 or mapping of DEFAULT_CHARSET */
880 if((psub->to.charset != psub->from.charset) ||
881 psub->to.charset == DEFAULT_CHARSET) {
882 HeapFree(GetProcessHeap(), 0, psub->to.name);
883 HeapFree(GetProcessHeap(), 0, psub->from.name);
884 HeapFree(GetProcessHeap(), 0, psub);
886 add_font_subst(&font_subst_list, psub, 0);
888 /* reset dlen and vlen */
892 HeapFree(GetProcessHeap(), 0, data);
893 HeapFree(GetProcessHeap(), 0, value);
898 static WCHAR *get_familyname(FT_Face ft_face)
900 WCHAR *family = NULL;
902 FT_UInt num_names, name_index, i;
904 if(FT_IS_SFNT(ft_face))
906 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
908 for(name_index = 0; name_index < num_names; name_index++)
910 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
912 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
913 (name.language_id == GetUserDefaultLCID()) &&
914 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
915 (name.encoding_id == TT_MS_ID_UNICODE_CS))
917 /* String is not nul terminated and string_len is a byte length. */
918 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
919 for(i = 0; i < name.string_len / 2; i++)
921 WORD *tmp = (WORD *)&name.string[i * 2];
922 family[i] = GET_BE_WORD(*tmp);
926 TRACE("Got localised name %s\n", debugstr_w(family));
937 #define ADDFONT_EXTERNAL_FONT 0x01
938 #define ADDFONT_FORCE_BITMAP 0x02
939 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
943 TT_Header *pHeader = NULL;
944 WCHAR *english_family, *localised_family, *StyleW;
948 struct list *family_elem_ptr, *face_elem_ptr;
950 FT_Long face_index = 0, num_faces;
951 #ifdef HAVE_FREETYPE_FTWINFNT_H
952 FT_WinFNT_HeaderRec winfnt_header;
954 int i, bitmap_num, internal_leading;
957 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
958 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
960 #ifdef HAVE_CARBON_CARBON_H
961 if(file && !fake_family)
963 char **mac_list = expand_mac_font(file);
966 BOOL had_one = FALSE;
968 for(cursor = mac_list; *cursor; cursor++)
971 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
972 HeapFree(GetProcessHeap(), 0, *cursor);
974 HeapFree(GetProcessHeap(), 0, mac_list);
979 #endif /* HAVE_CARBON_CARBON_H */
982 char *family_name = fake_family;
986 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
987 err = pFT_New_Face(library, file, face_index, &ft_face);
990 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
991 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
995 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
999 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1000 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1001 pFT_Done_Face(ft_face);
1005 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1006 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1007 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1008 pFT_Done_Face(ft_face);
1012 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
1013 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1014 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1015 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1016 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1017 pFT_Done_Face(ft_face);
1021 if(!ft_face->family_name || !ft_face->style_name) {
1022 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1023 pFT_Done_Face(ft_face);
1029 localised_family = get_familyname(ft_face);
1030 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1032 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1033 HeapFree(GetProcessHeap(), 0, localised_family);
1034 num_faces = ft_face->num_faces;
1035 pFT_Done_Face(ft_face);
1038 HeapFree(GetProcessHeap(), 0, localised_family);
1042 family_name = ft_face->family_name;
1046 My_FT_Bitmap_Size *size = NULL;
1049 if(!FT_IS_SCALABLE(ft_face))
1050 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1052 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1053 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1054 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1056 localised_family = NULL;
1058 localised_family = get_familyname(ft_face);
1059 if(localised_family && !strcmpW(localised_family, english_family)) {
1060 HeapFree(GetProcessHeap(), 0, localised_family);
1061 localised_family = NULL;
1066 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1067 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1068 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1073 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1074 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1075 list_init(&family->faces);
1076 list_add_tail(&font_list, &family->entry);
1078 if(localised_family) {
1079 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1080 subst->from.name = strdupW(english_family);
1081 subst->from.charset = -1;
1082 subst->to.name = strdupW(localised_family);
1083 subst->to.charset = -1;
1084 add_font_subst(&font_subst_list, subst, 0);
1087 HeapFree(GetProcessHeap(), 0, localised_family);
1088 HeapFree(GetProcessHeap(), 0, english_family);
1090 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1091 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1092 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1094 internal_leading = 0;
1095 memset(&fs, 0, sizeof(fs));
1097 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1099 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1100 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1101 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1102 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1103 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1104 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1105 if(pOS2->version == 0) {
1108 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1111 fs.fsCsb[0] |= 1L << 31;
1114 #ifdef HAVE_FREETYPE_FTWINFNT_H
1115 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1117 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1118 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1119 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1120 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1121 internal_leading = winfnt_header.internal_leading;
1125 face_elem_ptr = list_head(&family->faces);
1126 while(face_elem_ptr) {
1127 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1128 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1129 if(!strcmpW(face->StyleName, StyleW) &&
1130 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1131 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1132 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1133 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1136 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1137 HeapFree(GetProcessHeap(), 0, StyleW);
1138 pFT_Done_Face(ft_face);
1141 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1142 TRACE("Original font is newer so skipping this one\n");
1143 HeapFree(GetProcessHeap(), 0, StyleW);
1144 pFT_Done_Face(ft_face);
1147 TRACE("Replacing original with this one\n");
1148 list_remove(&face->entry);
1149 HeapFree(GetProcessHeap(), 0, face->file);
1150 HeapFree(GetProcessHeap(), 0, face->StyleName);
1151 HeapFree(GetProcessHeap(), 0, face);
1156 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1157 list_add_tail(&family->faces, &face->entry);
1158 face->StyleName = StyleW;
1161 face->file = strdupA(file);
1162 face->font_data_ptr = NULL;
1163 face->font_data_size = 0;
1168 face->font_data_ptr = font_data_ptr;
1169 face->font_data_size = font_data_size;
1171 face->face_index = face_index;
1172 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1173 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1174 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1175 face->family = family;
1176 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1177 memcpy(&face->fs, &fs, sizeof(face->fs));
1178 memset(&face->fs_links, 0, sizeof(face->fs_links));
1180 if(FT_IS_SCALABLE(ft_face)) {
1181 memset(&face->size, 0, sizeof(face->size));
1182 face->scalable = TRUE;
1184 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1185 size->height, size->width, size->size >> 6,
1186 size->x_ppem >> 6, size->y_ppem >> 6);
1187 face->size.height = size->height;
1188 face->size.width = size->width;
1189 face->size.size = size->size;
1190 face->size.x_ppem = size->x_ppem;
1191 face->size.y_ppem = size->y_ppem;
1192 face->size.internal_leading = internal_leading;
1193 face->scalable = FALSE;
1196 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1198 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, 0x43464620, 0, NULL, &tmp_size))
1200 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1201 face->ntmFlags = NTM_PS_OPENTYPE;
1206 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1207 face->fs.fsCsb[0], face->fs.fsCsb[1],
1208 face->fs.fsUsb[0], face->fs.fsUsb[1],
1209 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1212 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1213 for(i = 0; i < ft_face->num_charmaps; i++) {
1214 switch(ft_face->charmaps[i]->encoding) {
1215 case FT_ENCODING_UNICODE:
1216 case FT_ENCODING_APPLE_ROMAN:
1217 face->fs.fsCsb[0] |= 1;
1219 case FT_ENCODING_MS_SYMBOL:
1220 face->fs.fsCsb[0] |= 1L << 31;
1228 if(face->fs.fsCsb[0] & ~(1L << 31))
1229 have_installed_roman_font = TRUE;
1230 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1232 num_faces = ft_face->num_faces;
1233 pFT_Done_Face(ft_face);
1234 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1235 debugstr_w(StyleW));
1236 } while(num_faces > ++face_index);
1240 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1242 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1245 static void DumpFontList(void)
1249 struct list *family_elem_ptr, *face_elem_ptr;
1251 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1252 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1253 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1254 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1255 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1256 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1258 TRACE(" %d", face->size.height);
1265 /***********************************************************
1266 * The replacement list is a way to map an entire font
1267 * family onto another family. For example adding
1269 * [HKCU\Software\Wine\Fonts\Replacements]
1270 * "Wingdings"="Winedings"
1272 * would enumerate the Winedings font both as Winedings and
1273 * Wingdings. However if a real Wingdings font is present the
1274 * replacement does not take place.
1277 static void LoadReplaceList(void)
1280 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1285 struct list *family_elem_ptr, *face_elem_ptr;
1288 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1289 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1291 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1292 &valuelen, &datalen, NULL, NULL);
1294 valuelen++; /* returned value doesn't include room for '\0' */
1295 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1296 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1300 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1301 &dlen) == ERROR_SUCCESS) {
1302 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1303 /* "NewName"="Oldname" */
1304 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1306 /* Find the old family and hence all of the font files
1308 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1309 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1310 if(!strcmpiW(family->FamilyName, data)) {
1311 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1312 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1313 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1314 debugstr_w(face->StyleName), familyA);
1315 /* Now add a new entry with the new family name */
1316 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1321 /* reset dlen and vlen */
1325 HeapFree(GetProcessHeap(), 0, data);
1326 HeapFree(GetProcessHeap(), 0, value);
1331 /*************************************************************
1334 static BOOL init_system_links(void)
1336 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1337 'W','i','n','d','o','w','s',' ','N','T','\\',
1338 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1339 'S','y','s','t','e','m','L','i','n','k',0};
1342 DWORD type, max_val, max_data, val_len, data_len, index;
1343 WCHAR *value, *data;
1344 WCHAR *entry, *next;
1345 SYSTEM_LINKS *font_link, *system_font_link;
1346 CHILD_FONT *child_font;
1347 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1348 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1349 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1355 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1357 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1358 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1359 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1360 val_len = max_val + 1;
1361 data_len = max_data;
1363 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1365 TRACE("%s:\n", debugstr_w(value));
1367 memset(&fs, 0, sizeof(fs));
1368 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1369 psub = get_font_subst(&font_subst_list, value, -1);
1370 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1371 list_init(&font_link->links);
1372 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1375 CHILD_FONT *child_font;
1377 TRACE("\t%s\n", debugstr_w(entry));
1379 next = entry + strlenW(entry) + 1;
1381 face_name = strchrW(entry, ',');
1385 while(isspaceW(*face_name))
1388 psub = get_font_subst(&font_subst_list, face_name, -1);
1390 face_name = psub->to.name;
1392 face = find_face_from_filename(entry, face_name);
1395 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1399 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1400 child_font->face = face;
1401 child_font->font = NULL;
1402 fs.fsCsb[0] |= face->fs.fsCsb[0];
1403 fs.fsCsb[1] |= face->fs.fsCsb[1];
1404 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1405 list_add_tail(&font_link->links, &child_font->entry);
1407 family = find_family_from_name(font_link->font_name);
1410 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1412 memcpy(&face->fs_links, &fs, sizeof(fs));
1415 list_add_tail(&system_links, &font_link->entry);
1416 val_len = max_val + 1;
1417 data_len = max_data;
1420 HeapFree(GetProcessHeap(), 0, value);
1421 HeapFree(GetProcessHeap(), 0, data);
1425 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1428 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1429 system_font_link->font_name = strdupW(System);
1430 list_init(&system_font_link->links);
1432 face = find_face_from_filename(tahoma_ttf, Tahoma);
1435 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1436 child_font->face = face;
1437 child_font->font = NULL;
1438 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1439 list_add_tail(&system_font_link->links, &child_font->entry);
1441 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1443 if(!strcmpiW(font_link->font_name, Tahoma))
1445 CHILD_FONT *font_link_entry;
1446 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1448 CHILD_FONT *new_child;
1449 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1450 new_child->face = font_link_entry->face;
1451 new_child->font = NULL;
1452 list_add_tail(&system_font_link->links, &new_child->entry);
1457 list_add_tail(&system_links, &system_font_link->entry);
1461 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1464 struct dirent *dent;
1465 char path[MAX_PATH];
1467 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1469 dir = opendir(dirname);
1471 WARN("Can't open directory %s\n", debugstr_a(dirname));
1474 while((dent = readdir(dir)) != NULL) {
1475 struct stat statbuf;
1477 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1480 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1482 sprintf(path, "%s/%s", dirname, dent->d_name);
1484 if(stat(path, &statbuf) == -1)
1486 WARN("Can't stat %s\n", debugstr_a(path));
1489 if(S_ISDIR(statbuf.st_mode))
1490 ReadFontDir(path, external_fonts);
1492 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1498 static void load_fontconfig_fonts(void)
1500 #ifdef SONAME_LIBFONTCONFIG
1501 void *fc_handle = NULL;
1510 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1512 TRACE("Wine cannot find the fontconfig library (%s).\n",
1513 SONAME_LIBFONTCONFIG);
1516 #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;}
1517 LOAD_FUNCPTR(FcConfigGetCurrent);
1518 LOAD_FUNCPTR(FcFontList);
1519 LOAD_FUNCPTR(FcFontSetDestroy);
1520 LOAD_FUNCPTR(FcInit);
1521 LOAD_FUNCPTR(FcObjectSetAdd);
1522 LOAD_FUNCPTR(FcObjectSetCreate);
1523 LOAD_FUNCPTR(FcObjectSetDestroy);
1524 LOAD_FUNCPTR(FcPatternCreate);
1525 LOAD_FUNCPTR(FcPatternDestroy);
1526 LOAD_FUNCPTR(FcPatternGetBool);
1527 LOAD_FUNCPTR(FcPatternGetString);
1530 if(!pFcInit()) return;
1532 config = pFcConfigGetCurrent();
1533 pat = pFcPatternCreate();
1534 os = pFcObjectSetCreate();
1535 pFcObjectSetAdd(os, FC_FILE);
1536 pFcObjectSetAdd(os, FC_SCALABLE);
1537 fontset = pFcFontList(config, pat, os);
1538 if(!fontset) return;
1539 for(i = 0; i < fontset->nfont; i++) {
1542 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1544 TRACE("fontconfig: %s\n", file);
1546 /* We're just interested in OT/TT fonts for now, so this hack just
1547 picks up the scalable fonts without extensions .pf[ab] to save time
1548 loading every other font */
1550 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1552 TRACE("not scalable\n");
1556 len = strlen( file );
1557 if(len < 4) continue;
1558 ext = &file[ len - 3 ];
1559 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1560 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1562 pFcFontSetDestroy(fontset);
1563 pFcObjectSetDestroy(os);
1564 pFcPatternDestroy(pat);
1570 static BOOL load_font_from_data_dir(LPCWSTR file)
1573 const char *data_dir = wine_get_data_dir();
1575 if (!data_dir) data_dir = wine_get_build_dir();
1582 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1584 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1586 strcpy(unix_name, data_dir);
1587 strcat(unix_name, "/fonts/");
1589 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1591 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1592 HeapFree(GetProcessHeap(), 0, unix_name);
1597 static void load_system_fonts(void)
1600 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1601 const WCHAR * const *value;
1603 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1606 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1607 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1608 strcatW(windowsdir, fontsW);
1609 for(value = SystemFontValues; *value; value++) {
1610 dlen = sizeof(data);
1611 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1615 sprintfW(pathW, fmtW, windowsdir, data);
1616 if((unixname = wine_get_unix_file_name(pathW))) {
1617 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1618 HeapFree(GetProcessHeap(), 0, unixname);
1621 load_font_from_data_dir(data);
1628 /*************************************************************
1630 * This adds registry entries for any externally loaded fonts
1631 * (fonts from fontconfig or FontDirs). It also deletes entries
1632 * of no longer existing fonts.
1635 static void update_reg_entries(void)
1637 HKEY winkey = 0, externalkey = 0;
1640 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1643 struct list *family_elem_ptr, *face_elem_ptr;
1645 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1646 static const WCHAR spaceW[] = {' ', '\0'};
1649 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1650 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1651 ERR("Can't create Windows font reg key\n");
1654 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1655 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1656 ERR("Can't create external font reg key\n");
1660 /* Delete all external fonts added last time */
1662 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1663 &valuelen, &datalen, NULL, NULL);
1664 valuelen++; /* returned value doesn't include room for '\0' */
1665 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1666 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1668 dlen = datalen * sizeof(WCHAR);
1671 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1672 &dlen) == ERROR_SUCCESS) {
1674 RegDeleteValueW(winkey, valueW);
1675 /* reset dlen and vlen */
1679 HeapFree(GetProcessHeap(), 0, data);
1680 HeapFree(GetProcessHeap(), 0, valueW);
1682 /* Delete the old external fonts key */
1683 RegCloseKey(externalkey);
1685 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1687 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1688 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1689 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1690 ERR("Can't create external font reg key\n");
1694 /* enumerate the fonts and add external ones to the two keys */
1696 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1697 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1698 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1699 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1700 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1701 if(!face->external) continue;
1703 if(strcmpiW(face->StyleName, RegularW))
1704 len = len_fam + strlenW(face->StyleName) + 1;
1705 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1706 strcpyW(valueW, family->FamilyName);
1707 if(len != len_fam) {
1708 strcatW(valueW, spaceW);
1709 strcatW(valueW, face->StyleName);
1711 strcatW(valueW, TrueType);
1712 if((path = strrchr(face->file, '/')) == NULL)
1716 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1718 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1719 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1720 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1721 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1723 HeapFree(GetProcessHeap(), 0, file);
1724 HeapFree(GetProcessHeap(), 0, valueW);
1729 RegCloseKey(externalkey);
1731 RegCloseKey(winkey);
1736 /*************************************************************
1737 * WineEngAddFontResourceEx
1740 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1742 if (ft_handle) /* do it only if we have freetype up and running */
1747 FIXME("Ignoring flags %x\n", flags);
1749 if((unixname = wine_get_unix_file_name(file)))
1751 INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1752 HeapFree(GetProcessHeap(), 0, unixname);
1759 /*************************************************************
1760 * WineEngAddFontMemResourceEx
1763 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
1765 if (ft_handle) /* do it only if we have freetype up and running */
1767 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
1769 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
1770 memcpy(pFontCopy, pbFont, cbFont);
1772 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
1776 TRACE("AddFontToList failed\n");
1777 HeapFree(GetProcessHeap(), 0, pFontCopy);
1780 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1781 * For now return something unique but quite random
1783 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
1784 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
1791 /*************************************************************
1792 * WineEngRemoveFontResourceEx
1795 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1801 static const struct nls_update_font_list
1803 UINT ansi_cp, oem_cp;
1804 const char *oem, *fixed, *system;
1805 const char *courier, *serif, *small, *sserif;
1806 /* these are for font substitute */
1807 const char *shelldlg, *tmsrmn;
1808 } nls_update_font_list[] =
1810 /* Latin 1 (United States) */
1811 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1812 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1813 "Tahoma","Times New Roman",
1815 /* Latin 1 (Multilingual) */
1816 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1817 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1818 "Tahoma","Times New Roman", /* FIXME unverified */
1820 /* Eastern Europe */
1821 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1822 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1823 "Tahoma","Times New Roman", /* FIXME unverified */
1826 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1827 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1828 "Tahoma","Times New Roman", /* FIXME unverified */
1831 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1832 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1833 "Tahoma","Times New Roman", /* FIXME unverified */
1836 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1837 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1838 "Tahoma","Times New Roman", /* FIXME unverified */
1841 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1842 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1843 "Tahoma","Times New Roman", /* FIXME unverified */
1846 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1847 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1848 "Tahoma","Times New Roman", /* FIXME unverified */
1851 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1852 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1853 "Tahoma","Times New Roman", /* FIXME unverified */
1856 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1857 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1858 "Tahoma","Times New Roman", /* FIXME unverified */
1861 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1862 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1863 "Tahoma","Times New Roman", /* FIXME unverified */
1866 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1867 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1868 "MS UI Gothic","MS Serif",
1870 /* Chinese Simplified */
1871 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1872 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1873 "Tahoma", "Times New Roman", /* FIXME unverified */
1876 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1877 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1880 /* Chinese Traditional */
1881 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1882 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1883 "Tahoma", "Times New Roman", /* FIXME unverified */
1887 static inline HKEY create_fonts_NT_registry_key(void)
1891 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1892 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1896 static inline HKEY create_fonts_9x_registry_key(void)
1900 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1901 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1905 static inline HKEY create_config_fonts_registry_key(void)
1909 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1910 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1914 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1916 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1917 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1918 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1919 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1922 static void update_font_info(void)
1924 char buf[40], cpbuf[40];
1927 UINT i, ansi_cp = 0, oem_cp = 0;
1929 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1932 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1933 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1934 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1935 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1936 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1939 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1941 if (!strcmp( buf, cpbuf )) /* already set correctly */
1946 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1948 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1950 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1953 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1955 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1956 nls_update_font_list[i].oem_cp == oem_cp)
1960 hkey = create_config_fonts_registry_key();
1961 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1962 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1963 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1966 hkey = create_fonts_NT_registry_key();
1967 add_font_list(hkey, &nls_update_font_list[i]);
1970 hkey = create_fonts_9x_registry_key();
1971 add_font_list(hkey, &nls_update_font_list[i]);
1974 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
1976 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
1977 strlen(nls_update_font_list[i].shelldlg)+1);
1978 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
1979 strlen(nls_update_font_list[i].tmsrmn)+1);
1985 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1988 /*************************************************************
1991 * Initialize FreeType library and create a list of available faces
1993 BOOL WineEngInit(void)
1995 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1996 static const WCHAR pathW[] = {'P','a','t','h',0};
1998 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2000 WCHAR windowsdir[MAX_PATH];
2003 const char *data_dir;
2007 /* update locale dependent font info in registry */
2010 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2013 "Wine cannot find the FreeType font library. To enable Wine to\n"
2014 "use TrueType fonts please install a version of FreeType greater than\n"
2015 "or equal to 2.0.5.\n"
2016 "http://www.freetype.org\n");
2020 #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;}
2022 LOAD_FUNCPTR(FT_Vector_Unit)
2023 LOAD_FUNCPTR(FT_Done_Face)
2024 LOAD_FUNCPTR(FT_Get_Char_Index)
2025 LOAD_FUNCPTR(FT_Get_Module)
2026 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2027 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2028 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2029 LOAD_FUNCPTR(FT_Init_FreeType)
2030 LOAD_FUNCPTR(FT_Load_Glyph)
2031 LOAD_FUNCPTR(FT_Matrix_Multiply)
2032 LOAD_FUNCPTR(FT_MulFix)
2033 LOAD_FUNCPTR(FT_New_Face)
2034 LOAD_FUNCPTR(FT_New_Memory_Face)
2035 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2036 LOAD_FUNCPTR(FT_Outline_Transform)
2037 LOAD_FUNCPTR(FT_Outline_Translate)
2038 LOAD_FUNCPTR(FT_Select_Charmap)
2039 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2040 LOAD_FUNCPTR(FT_Vector_Transform)
2043 /* Don't warn if this one is missing */
2044 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2045 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2046 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2047 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2048 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2049 #ifdef HAVE_FREETYPE_FTWINFNT_H
2050 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2052 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2053 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2054 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2055 <= 2.0.3 has FT_Sqrt64 */
2059 if(pFT_Init_FreeType(&library) != 0) {
2060 ERR("Can't init FreeType library\n");
2061 wine_dlclose(ft_handle, NULL, 0);
2065 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2066 if (pFT_Library_Version)
2068 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2070 if (FT_Version.major<=0)
2076 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2077 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2078 ((FT_Version.minor << 8) & 0x00ff00) |
2079 ((FT_Version.patch ) & 0x0000ff);
2081 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2082 ERR("Failed to create font mutex\n");
2085 WaitForSingleObject(font_mutex, INFINITE);
2087 /* load the system bitmap fonts */
2088 load_system_fonts();
2090 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2091 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2092 strcatW(windowsdir, fontsW);
2093 if((unixname = wine_get_unix_file_name(windowsdir)))
2095 ReadFontDir(unixname, FALSE);
2096 HeapFree(GetProcessHeap(), 0, unixname);
2099 /* load the system truetype fonts */
2100 data_dir = wine_get_data_dir();
2101 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2102 strcpy(unixname, data_dir);
2103 strcat(unixname, "/fonts/");
2104 ReadFontDir(unixname, FALSE);
2105 HeapFree(GetProcessHeap(), 0, unixname);
2108 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2109 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2110 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2112 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2113 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2114 &hkey) == ERROR_SUCCESS) {
2116 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2117 &valuelen, &datalen, NULL, NULL);
2119 valuelen++; /* returned value doesn't include room for '\0' */
2120 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2121 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2124 dlen = datalen * sizeof(WCHAR);
2126 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2127 &dlen) == ERROR_SUCCESS) {
2128 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2130 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2132 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2133 HeapFree(GetProcessHeap(), 0, unixname);
2136 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2138 WCHAR pathW[MAX_PATH];
2139 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2142 sprintfW(pathW, fmtW, windowsdir, data);
2143 if((unixname = wine_get_unix_file_name(pathW)))
2145 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2146 HeapFree(GetProcessHeap(), 0, unixname);
2149 load_font_from_data_dir(data);
2151 /* reset dlen and vlen */
2156 HeapFree(GetProcessHeap(), 0, data);
2157 HeapFree(GetProcessHeap(), 0, valueW);
2161 load_fontconfig_fonts();
2163 /* then look in any directories that we've specified in the config file */
2164 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2165 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2171 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2173 len += sizeof(WCHAR);
2174 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2175 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2177 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2178 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2179 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2180 TRACE( "got font path %s\n", debugstr_a(valueA) );
2184 LPSTR next = strchr( ptr, ':' );
2185 if (next) *next++ = 0;
2186 ReadFontDir( ptr, TRUE );
2189 HeapFree( GetProcessHeap(), 0, valueA );
2191 HeapFree( GetProcessHeap(), 0, valueW );
2200 update_reg_entries();
2202 init_system_links();
2204 ReleaseMutex(font_mutex);
2208 "Wine cannot find certain functions that it needs inside the FreeType\n"
2209 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2210 "FreeType to at least version 2.0.5.\n"
2211 "http://www.freetype.org\n");
2212 wine_dlclose(ft_handle, NULL, 0);
2218 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2221 TT_HoriHeader *pHori;
2225 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2226 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2228 if(height == 0) height = 16;
2230 /* Calc. height of EM square:
2232 * For +ve lfHeight we have
2233 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2234 * Re-arranging gives:
2235 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2237 * For -ve lfHeight we have
2239 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2240 * with il = winAscent + winDescent - units_per_em]
2245 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2246 ppem = ft_face->units_per_EM * height /
2247 (pHori->Ascender - pHori->Descender);
2249 ppem = ft_face->units_per_EM * height /
2250 (pOS2->usWinAscent + pOS2->usWinDescent);
2258 static struct font_mapping *map_font_file( const char *name )
2260 struct font_mapping *mapping;
2264 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2265 if (fstat( fd, &st ) == -1) goto error;
2267 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2269 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2271 mapping->refcount++;
2276 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2279 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2282 if (mapping->data == MAP_FAILED)
2284 HeapFree( GetProcessHeap(), 0, mapping );
2287 mapping->refcount = 1;
2288 mapping->dev = st.st_dev;
2289 mapping->ino = st.st_ino;
2290 mapping->size = st.st_size;
2291 list_add_tail( &mappings_list, &mapping->entry );
2299 static void unmap_font_file( struct font_mapping *mapping )
2301 if (!--mapping->refcount)
2303 list_remove( &mapping->entry );
2304 munmap( mapping->data, mapping->size );
2305 HeapFree( GetProcessHeap(), 0, mapping );
2309 static LONG load_VDMX(GdiFont*, LONG);
2311 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2318 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2322 if (!(font->mapping = map_font_file( face->file )))
2324 WARN("failed to map %s\n", debugstr_a(face->file));
2327 data_ptr = font->mapping->data;
2328 data_size = font->mapping->size;
2332 data_ptr = face->font_data_ptr;
2333 data_size = face->font_data_size;
2336 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2338 ERR("FT_New_Face rets %d\n", err);
2342 /* set it here, as load_VDMX needs it */
2343 font->ft_face = ft_face;
2345 if(FT_IS_SCALABLE(ft_face)) {
2346 /* load the VDMX table if we have one */
2347 font->ppem = load_VDMX(font, height);
2349 font->ppem = calc_ppem_for_height(ft_face, height);
2351 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2352 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2354 font->ppem = height;
2355 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2356 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2362 static int get_nearest_charset(Face *face, int *cp)
2364 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2365 a single face with the requested charset. The idea is to check if
2366 the selected font supports the current ANSI codepage, if it does
2367 return the corresponding charset, else return the first charset */
2370 int acp = GetACP(), i;
2374 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2375 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2376 return csi.ciCharset;
2378 for(i = 0; i < 32; i++) {
2380 if(face->fs.fsCsb[0] & fs0) {
2381 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2383 return csi.ciCharset;
2386 FIXME("TCI failing on %x\n", fs0);
2390 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2391 face->fs.fsCsb[0], face->file);
2393 return DEFAULT_CHARSET;
2396 static GdiFont *alloc_font(void)
2398 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2400 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2401 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2403 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2404 ret->total_kern_pairs = (DWORD)-1;
2405 ret->kern_pairs = NULL;
2406 list_init(&ret->hfontlist);
2407 list_init(&ret->child_fonts);
2411 static void free_font(GdiFont *font)
2413 struct list *cursor, *cursor2;
2416 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2418 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2419 struct list *first_hfont;
2420 HFONTLIST *hfontlist;
2421 list_remove(cursor);
2424 first_hfont = list_head(&child->font->hfontlist);
2425 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2426 DeleteObject(hfontlist->hfont);
2427 HeapFree(GetProcessHeap(), 0, hfontlist);
2428 free_font(child->font);
2430 HeapFree(GetProcessHeap(), 0, child);
2433 if (font->ft_face) pFT_Done_Face(font->ft_face);
2434 if (font->mapping) unmap_font_file( font->mapping );
2435 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2436 HeapFree(GetProcessHeap(), 0, font->potm);
2437 HeapFree(GetProcessHeap(), 0, font->name);
2438 for (i = 0; i < font->gmsize; i++)
2439 HeapFree(GetProcessHeap(),0,font->gm[i]);
2440 HeapFree(GetProcessHeap(), 0, font->gm);
2441 HeapFree(GetProcessHeap(), 0, font);
2445 /*************************************************************
2448 * load the vdmx entry for the specified height
2451 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2452 ( ( (FT_ULong)_x4 << 24 ) | \
2453 ( (FT_ULong)_x3 << 16 ) | \
2454 ( (FT_ULong)_x2 << 8 ) | \
2457 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2472 static LONG load_VDMX(GdiFont *font, LONG height)
2476 BYTE devXRatio, devYRatio;
2477 USHORT numRecs, numRatios;
2478 DWORD result, offset = -1;
2482 /* For documentation on VDMX records, see
2483 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2486 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2488 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2491 /* FIXME: need the real device aspect ratio */
2495 numRecs = GET_BE_WORD(hdr[1]);
2496 numRatios = GET_BE_WORD(hdr[2]);
2498 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2499 for(i = 0; i < numRatios; i++) {
2502 offset = (3 * 2) + (i * sizeof(Ratios));
2503 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2506 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2508 if((ratio.xRatio == 0 &&
2509 ratio.yStartRatio == 0 &&
2510 ratio.yEndRatio == 0) ||
2511 (devXRatio == ratio.xRatio &&
2512 devYRatio >= ratio.yStartRatio &&
2513 devYRatio <= ratio.yEndRatio))
2515 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2516 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2517 offset = GET_BE_WORD(tmp);
2523 FIXME("No suitable ratio found\n");
2527 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2529 BYTE startsz, endsz;
2532 recs = GET_BE_WORD(group.recs);
2533 startsz = group.startsz;
2534 endsz = group.endsz;
2536 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2538 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2539 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2540 if(result == GDI_ERROR) {
2541 FIXME("Failed to retrieve vTable\n");
2546 for(i = 0; i < recs; i++) {
2547 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2548 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2549 ppem = GET_BE_WORD(vTable[i * 3]);
2551 if(yMax + -yMin == height) {
2554 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2557 if(yMax + -yMin > height) {
2560 goto end; /* failed */
2562 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2563 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2564 ppem = GET_BE_WORD(vTable[i * 3]);
2565 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2571 TRACE("ppem not found for height %d\n", height);
2575 if(ppem < startsz || ppem > endsz)
2578 for(i = 0; i < recs; i++) {
2580 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2582 if(yPelHeight > ppem)
2585 if(yPelHeight == ppem) {
2586 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2587 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2588 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2594 HeapFree(GetProcessHeap(), 0, vTable);
2600 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2602 if(font->font_desc.hash != fd->hash) return TRUE;
2603 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2604 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2605 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2606 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2609 static void calc_hash(FONT_DESC *pfd)
2611 DWORD hash = 0, *ptr, two_chars;
2615 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2617 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2619 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2621 pwc = (WCHAR *)&two_chars;
2623 *pwc = toupperW(*pwc);
2625 *pwc = toupperW(*pwc);
2629 hash ^= !pfd->can_use_bitmap;
2634 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2639 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2641 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2642 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2643 fd.can_use_bitmap = can_use_bitmap;
2646 /* try the in-use list */
2647 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2648 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2649 if(!fontcmp(ret, &fd)) {
2650 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2651 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2652 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2653 if(hflist->hfont == hfont)
2656 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2657 hflist->hfont = hfont;
2658 list_add_head(&ret->hfontlist, &hflist->entry);
2663 /* then the unused list */
2664 font_elem_ptr = list_head(&unused_gdi_font_list);
2665 while(font_elem_ptr) {
2666 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2667 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2668 if(!fontcmp(ret, &fd)) {
2669 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2670 assert(list_empty(&ret->hfontlist));
2671 TRACE("Found %p in unused list\n", ret);
2672 list_remove(&ret->entry);
2673 list_add_head(&gdi_font_list, &ret->entry);
2674 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2675 hflist->hfont = hfont;
2676 list_add_head(&ret->hfontlist, &hflist->entry);
2684 /*************************************************************
2685 * create_child_font_list
2687 static BOOL create_child_font_list(GdiFont *font)
2690 SYSTEM_LINKS *font_link;
2691 CHILD_FONT *font_link_entry, *new_child;
2693 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2695 if(!strcmpW(font_link->font_name, font->name))
2697 TRACE("found entry in system list\n");
2698 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2700 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2701 new_child->face = font_link_entry->face;
2702 new_child->font = NULL;
2703 list_add_tail(&font->child_fonts, &new_child->entry);
2704 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2714 /*************************************************************
2715 * WineEngCreateFontInstance
2718 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2721 Face *face, *best, *best_bitmap;
2722 Family *family, *last_resort_family;
2723 struct list *family_elem_ptr, *face_elem_ptr;
2724 INT height, width = 0;
2725 unsigned int score = 0, new_score;
2726 signed int diff = 0, newdiff;
2727 BOOL bd, it, can_use_bitmap;
2732 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2734 struct list *first_hfont = list_head(&ret->hfontlist);
2735 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2736 if(hflist->hfont == hfont)
2740 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2741 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2743 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2744 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2745 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2748 /* check the cache first */
2749 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2750 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2754 TRACE("not in cache\n");
2755 if(list_empty(&font_list)) /* No fonts installed */
2757 TRACE("No fonts installed\n");
2760 if(!have_installed_roman_font)
2762 TRACE("No roman font installed\n");
2768 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2769 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2770 ret->font_desc.can_use_bitmap = can_use_bitmap;
2771 calc_hash(&ret->font_desc);
2772 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2773 hflist->hfont = hfont;
2774 list_add_head(&ret->hfontlist, &hflist->entry);
2777 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2778 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2779 original value lfCharSet. Note this is a special case for
2780 Symbol and doesn't happen at least for "Wingdings*" */
2782 if(!strcmpiW(lf.lfFaceName, SymbolW))
2783 lf.lfCharSet = SYMBOL_CHARSET;
2785 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2786 switch(lf.lfCharSet) {
2787 case DEFAULT_CHARSET:
2788 csi.fs.fsCsb[0] = 0;
2791 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2792 csi.fs.fsCsb[0] = 0;
2798 if(lf.lfFaceName[0] != '\0') {
2800 SYSTEM_LINKS *font_link;
2801 CHILD_FONT *font_link_entry;
2803 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2806 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2807 debugstr_w(psub->to.name));
2808 strcpyW(lf.lfFaceName, psub->to.name);
2811 /* We want a match on name and charset or just name if
2812 charset was DEFAULT_CHARSET. If the latter then
2813 we fixup the returned charset later in get_nearest_charset
2814 where we'll either use the charset of the current ansi codepage
2815 or if that's unavailable the first charset that the font supports.
2817 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2818 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2819 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2820 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2821 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2822 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2823 if(face->scalable || can_use_bitmap)
2830 * Try check the SystemLink list first for a replacement font.
2831 * We may find good replacements there.
2833 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2835 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2837 TRACE("found entry in system list\n");
2838 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2840 face = font_link_entry->face;
2841 family = face->family;
2842 if(csi.fs.fsCsb[0] &
2843 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2845 if(face->scalable || can_use_bitmap)
2853 /* If requested charset was DEFAULT_CHARSET then try using charset
2854 corresponding to the current ansi codepage */
2855 if(!csi.fs.fsCsb[0]) {
2857 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2858 FIXME("TCI failed on codepage %d\n", acp);
2859 csi.fs.fsCsb[0] = 0;
2861 lf.lfCharSet = csi.ciCharset;
2864 /* Face families are in the top 4 bits of lfPitchAndFamily,
2865 so mask with 0xF0 before testing */
2867 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2868 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2869 strcpyW(lf.lfFaceName, defFixed);
2870 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2871 strcpyW(lf.lfFaceName, defSerif);
2872 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2873 strcpyW(lf.lfFaceName, defSans);
2875 strcpyW(lf.lfFaceName, defSans);
2876 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2877 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2878 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2879 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2880 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2881 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2882 if(face->scalable || can_use_bitmap)
2888 last_resort_family = NULL;
2889 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2890 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2891 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2892 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2893 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2896 if(can_use_bitmap && !last_resort_family)
2897 last_resort_family = family;
2902 if(last_resort_family) {
2903 family = last_resort_family;
2904 csi.fs.fsCsb[0] = 0;
2908 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2909 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2910 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2911 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2912 if(face->scalable) {
2913 csi.fs.fsCsb[0] = 0;
2914 WARN("just using first face for now\n");
2917 if(can_use_bitmap && !last_resort_family)
2918 last_resort_family = family;
2921 if(!last_resort_family) {
2922 FIXME("can't find a single appropriate font - bailing\n");
2927 WARN("could only find a bitmap font - this will probably look awful!\n");
2928 family = last_resort_family;
2929 csi.fs.fsCsb[0] = 0;
2932 it = lf.lfItalic ? 1 : 0;
2933 bd = lf.lfWeight > 550 ? 1 : 0;
2935 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2936 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2938 face = best = best_bitmap = NULL;
2939 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2941 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2943 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2944 if(!best || new_score <= score)
2946 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2947 face->Italic, face->Bold, it, bd);
2950 if(best->scalable && score == 0) break;
2954 newdiff = height - (signed int)(best->size.height);
2956 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2957 if(!best_bitmap || new_score < score ||
2958 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2960 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2963 if(score == 0 && diff == 0) break;
2970 face = best->scalable ? best : best_bitmap;
2971 ret->fake_italic = (it && !face->Italic);
2972 ret->fake_bold = (bd && !face->Bold);
2974 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2976 if(csi.fs.fsCsb[0]) {
2977 ret->charset = lf.lfCharSet;
2978 ret->codepage = csi.ciACP;
2981 ret->charset = get_nearest_charset(face, &ret->codepage);
2983 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
2984 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
2986 if(!face->scalable) {
2987 width = face->size.x_ppem >> 6;
2988 height = face->size.y_ppem >> 6;
2990 ret->ft_face = OpenFontFace(ret, face, width, height);
2998 ret->ntmFlags = face->ntmFlags;
3000 if (ret->charset == SYMBOL_CHARSET &&
3001 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3004 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3008 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3011 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3012 ret->name = strdupW(family->FamilyName);
3013 ret->underline = lf.lfUnderline ? 0xff : 0;
3014 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3015 create_child_font_list(ret);
3017 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3019 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
3020 list_add_head(&gdi_font_list, &ret->entry);
3024 static void dump_gdi_font_list(void)
3027 struct list *elem_ptr;
3029 TRACE("---------- gdiFont Cache ----------\n");
3030 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3031 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3032 TRACE("gdiFont=%p %s %d\n",
3033 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3036 TRACE("---------- Unused gdiFont Cache ----------\n");
3037 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3038 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3039 TRACE("gdiFont=%p %s %d\n",
3040 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3044 /*************************************************************
3045 * WineEngDestroyFontInstance
3047 * free the gdiFont associated with this handle
3050 BOOL WineEngDestroyFontInstance(HFONT handle)
3055 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3058 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3060 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3061 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3062 if(hflist->hfont == handle)
3064 TRACE("removing child font %p from child list\n", gdiFont);
3065 list_remove(&gdiFont->entry);
3070 TRACE("destroying hfont=%p\n", handle);
3072 dump_gdi_font_list();
3074 font_elem_ptr = list_head(&gdi_font_list);
3075 while(font_elem_ptr) {
3076 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3077 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3079 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3080 while(hfontlist_elem_ptr) {
3081 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3082 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3083 if(hflist->hfont == handle) {
3084 list_remove(&hflist->entry);
3085 HeapFree(GetProcessHeap(), 0, hflist);
3089 if(list_empty(&gdiFont->hfontlist)) {
3090 TRACE("Moving to Unused list\n");
3091 list_remove(&gdiFont->entry);
3092 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3097 font_elem_ptr = list_head(&unused_gdi_font_list);
3098 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3099 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3100 while(font_elem_ptr) {
3101 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3102 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3103 TRACE("freeing %p\n", gdiFont);
3104 list_remove(&gdiFont->entry);
3110 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3111 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3113 OUTLINETEXTMETRICW *potm = NULL;
3115 TEXTMETRICW tm, *ptm;
3116 GdiFont *font = alloc_font();
3119 if(face->scalable) {
3123 height = face->size.y_ppem >> 6;
3124 width = face->size.x_ppem >> 6;
3127 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3133 font->name = strdupW(face->family->FamilyName);
3134 font->ntmFlags = face->ntmFlags;
3136 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3138 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3140 potm = HeapAlloc(GetProcessHeap(), 0, size);
3141 WineEngGetOutlineTextMetrics(font, size, potm);
3142 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3144 WineEngGetTextMetrics(font, &tm);
3148 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3149 pntm->ntmTm.tmAscent = ptm->tmAscent;
3150 pntm->ntmTm.tmDescent = ptm->tmDescent;
3151 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3152 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3153 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3154 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3155 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3156 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3157 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3158 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3159 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3160 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3161 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3162 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3163 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3164 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3165 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3166 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3167 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3168 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3169 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3170 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3171 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3174 if (ptm->tmPitchAndFamily & TMPF_TRUETYPE)
3175 *ptype |= TRUETYPE_FONTTYPE;
3176 if (ptm->tmPitchAndFamily & TMPF_DEVICE)
3177 *ptype |= DEVICE_FONTTYPE;
3178 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3179 *ptype |= RASTER_FONTTYPE;
3181 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3182 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3183 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3184 pntm->ntmTm.ntmFlags |= face->ntmFlags;
3186 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3187 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3188 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3191 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3193 lstrcpynW(pelf->elfLogFont.lfFaceName,
3194 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3196 lstrcpynW(pelf->elfFullName,
3197 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3199 lstrcpynW(pelf->elfStyle,
3200 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3203 HeapFree(GetProcessHeap(), 0, potm);
3205 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3207 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3208 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3209 pelf->elfStyle[0] = '\0';
3212 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3217 /*************************************************************
3221 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3225 struct list *family_elem_ptr, *face_elem_ptr;
3227 NEWTEXTMETRICEXW ntm;
3228 DWORD type, ret = 1;
3234 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3236 if(plf->lfFaceName[0]) {
3238 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3241 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3242 debugstr_w(psub->to.name));
3243 memcpy(&lf, plf, sizeof(lf));
3244 strcpyW(lf.lfFaceName, psub->to.name);
3248 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3249 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3250 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3251 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3252 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3253 GetEnumStructs(face, &elf, &ntm, &type);
3254 for(i = 0; i < 32; i++) {
3255 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3256 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3257 strcpyW(elf.elfScript, OEM_DOSW);
3258 i = 32; /* break out of loop */
3259 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3262 fs.fsCsb[0] = 1L << i;
3264 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3266 csi.ciCharset = DEFAULT_CHARSET;
3267 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3268 if(csi.ciCharset != DEFAULT_CHARSET) {
3269 elf.elfLogFont.lfCharSet =
3270 ntm.ntmTm.tmCharSet = csi.ciCharset;
3272 strcpyW(elf.elfScript, ElfScriptsW[i]);
3274 FIXME("Unknown elfscript for bit %d\n", i);
3277 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3278 debugstr_w(elf.elfLogFont.lfFaceName),
3279 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3280 csi.ciCharset, type, debugstr_w(elf.elfScript),
3281 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3282 ntm.ntmTm.ntmFlags);
3283 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3290 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3291 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3292 face_elem_ptr = list_head(&family->faces);
3293 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3294 GetEnumStructs(face, &elf, &ntm, &type);
3295 for(i = 0; i < 32; i++) {
3296 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3297 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3298 strcpyW(elf.elfScript, OEM_DOSW);
3299 i = 32; /* break out of loop */
3300 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3303 fs.fsCsb[0] = 1L << i;
3305 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3307 csi.ciCharset = DEFAULT_CHARSET;
3308 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3309 if(csi.ciCharset != DEFAULT_CHARSET) {
3310 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3313 strcpyW(elf.elfScript, ElfScriptsW[i]);
3315 FIXME("Unknown elfscript for bit %d\n", i);
3318 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3319 debugstr_w(elf.elfLogFont.lfFaceName),
3320 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3321 csi.ciCharset, type, debugstr_w(elf.elfScript),
3322 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3323 ntm.ntmTm.ntmFlags);
3324 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3333 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3335 pt->x.value = vec->x >> 6;
3336 pt->x.fract = (vec->x & 0x3f) << 10;
3337 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3338 pt->y.value = vec->y >> 6;
3339 pt->y.fract = (vec->y & 0x3f) << 10;
3340 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3344 /***************************************************
3345 * According to the MSDN documentation on WideCharToMultiByte,
3346 * certain codepages cannot set the default_used parameter.
3347 * This returns TRUE if the codepage can set that parameter, false else
3348 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3350 static BOOL codepage_sets_default_used(UINT codepage)
3363 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3365 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3366 WCHAR wc = (WCHAR)glyph;
3368 BOOL *default_used_pointer;
3371 default_used_pointer = NULL;
3372 default_used = FALSE;
3373 if (codepage_sets_default_used(font->codepage))
3374 default_used_pointer = &default_used;
3375 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3378 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3379 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3383 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3384 glyph = glyph + 0xf000;
3385 return pFT_Get_Char_Index(font->ft_face, glyph);
3388 /*************************************************************
3389 * WineEngGetGlyphIndices
3391 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3393 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3394 LPWORD pgi, DWORD flags)
3397 WCHAR default_char = 0;
3400 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3402 for(i = 0; i < count; i++)
3404 pgi[i] = get_glyph_index(font, lpstr[i]);
3409 WineEngGetTextMetrics(font, &textm);
3410 default_char = textm.tmDefaultChar;
3412 pgi[i] = default_char;
3418 /*************************************************************
3419 * WineEngGetGlyphOutline
3421 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3422 * except that the first parameter is the HWINEENGFONT of the font in
3423 * question rather than an HDC.
3426 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3427 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3430 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3431 FT_Face ft_face = incoming_font->ft_face;
3432 GdiFont *font = incoming_font;
3433 FT_UInt glyph_index;
3434 DWORD width, height, pitch, needed = 0;
3435 FT_Bitmap ft_bitmap;
3437 INT left, right, top = 0, bottom = 0;
3439 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3440 float widthRatio = 1.0;
3441 FT_Matrix transMat = identityMat;
3442 BOOL needsTransform = FALSE;
3445 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3446 buflen, buf, lpmat);
3448 if(format & GGO_GLYPH_INDEX) {
3449 glyph_index = glyph;
3450 format &= ~GGO_GLYPH_INDEX;
3452 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3453 ft_face = font->ft_face;
3456 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3457 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3458 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3459 font->gmsize * sizeof(GM*));
3461 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3462 *lpgm = FONT_GM(font,glyph_index)->gm;
3463 return 1; /* FIXME */
3467 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3468 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3470 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
3471 load_flags |= FT_LOAD_NO_BITMAP;
3473 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3476 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3480 /* Scaling factor */
3481 if (font->aveWidth && font->potm) {
3482 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3485 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3486 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3488 FONT_GM(font,glyph_index)->adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3489 FONT_GM(font,glyph_index)->lsb = left >> 6;
3490 FONT_GM(font,glyph_index)->bbx = (right - left) >> 6;
3492 /* Scaling transform */
3493 if(font->aveWidth) {
3495 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3498 scaleMat.yy = (1 << 16);
3500 pFT_Matrix_Multiply(&scaleMat, &transMat);
3501 needsTransform = TRUE;
3504 /* Slant transform */
3505 if (font->fake_italic) {
3508 slantMat.xx = (1 << 16);
3509 slantMat.xy = ((1 << 16) >> 2);
3511 slantMat.yy = (1 << 16);
3512 pFT_Matrix_Multiply(&slantMat, &transMat);
3513 needsTransform = TRUE;
3516 /* Rotation transform */
3517 if(font->orientation) {
3518 FT_Matrix rotationMat;
3520 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3521 pFT_Vector_Unit(&vecAngle, angle);
3522 rotationMat.xx = vecAngle.x;
3523 rotationMat.xy = -vecAngle.y;
3524 rotationMat.yx = -rotationMat.xy;
3525 rotationMat.yy = rotationMat.xx;
3527 pFT_Matrix_Multiply(&rotationMat, &transMat);
3528 needsTransform = TRUE;
3531 /* Extra transformation specified by caller */
3534 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3535 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3536 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3537 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3538 pFT_Matrix_Multiply(&extraMat, &transMat);
3539 needsTransform = TRUE;
3542 if(!needsTransform) {
3543 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3544 bottom = (ft_face->glyph->metrics.horiBearingY -
3545 ft_face->glyph->metrics.height) & -64;
3546 lpgm->gmCellIncX = FONT_GM(font,glyph_index)->adv;
3547 lpgm->gmCellIncY = 0;
3551 for(xc = 0; xc < 2; xc++) {
3552 for(yc = 0; yc < 2; yc++) {
3553 vec.x = (ft_face->glyph->metrics.horiBearingX +
3554 xc * ft_face->glyph->metrics.width);
3555 vec.y = ft_face->glyph->metrics.horiBearingY -
3556 yc * ft_face->glyph->metrics.height;
3557 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3558 pFT_Vector_Transform(&vec, &transMat);
3559 if(xc == 0 && yc == 0) {
3560 left = right = vec.x;
3561 top = bottom = vec.y;
3563 if(vec.x < left) left = vec.x;
3564 else if(vec.x > right) right = vec.x;
3565 if(vec.y < bottom) bottom = vec.y;
3566 else if(vec.y > top) top = vec.y;
3571 right = (right + 63) & -64;
3572 bottom = bottom & -64;
3573 top = (top + 63) & -64;
3575 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3576 vec.x = ft_face->glyph->metrics.horiAdvance;
3578 pFT_Vector_Transform(&vec, &transMat);
3579 lpgm->gmCellIncX = (vec.x+63) >> 6;
3580 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3582 lpgm->gmBlackBoxX = (right - left) >> 6;
3583 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3584 lpgm->gmptGlyphOrigin.x = left >> 6;
3585 lpgm->gmptGlyphOrigin.y = top >> 6;
3587 FONT_GM(font,glyph_index)->gm = *lpgm;
3588 FONT_GM(font,glyph_index)->init = TRUE;
3590 if(format == GGO_METRICS)
3591 return 1; /* FIXME */
3593 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3594 TRACE("loaded a bitmap\n");
3600 width = lpgm->gmBlackBoxX;
3601 height = lpgm->gmBlackBoxY;
3602 pitch = ((width + 31) >> 5) << 2;
3603 needed = pitch * height;
3605 if(!buf || !buflen) break;
3607 switch(ft_face->glyph->format) {
3608 case ft_glyph_format_bitmap:
3610 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3611 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3612 INT h = ft_face->glyph->bitmap.rows;
3614 memcpy(dst, src, w);
3615 src += ft_face->glyph->bitmap.pitch;
3621 case ft_glyph_format_outline:
3622 ft_bitmap.width = width;
3623 ft_bitmap.rows = height;
3624 ft_bitmap.pitch = pitch;
3625 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3626 ft_bitmap.buffer = buf;
3628 if(needsTransform) {
3629 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3632 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3634 /* Note: FreeType will only set 'black' bits for us. */
3635 memset(buf, 0, needed);
3636 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3640 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3645 case GGO_GRAY2_BITMAP:
3646 case GGO_GRAY4_BITMAP:
3647 case GGO_GRAY8_BITMAP:
3648 case WINE_GGO_GRAY16_BITMAP:
3650 unsigned int mult, row, col;
3653 width = lpgm->gmBlackBoxX;
3654 height = lpgm->gmBlackBoxY;
3655 pitch = (width + 3) / 4 * 4;
3656 needed = pitch * height;
3658 if(!buf || !buflen) break;
3659 ft_bitmap.width = width;
3660 ft_bitmap.rows = height;
3661 ft_bitmap.pitch = pitch;
3662 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3663 ft_bitmap.buffer = buf;
3665 if(needsTransform) {
3666 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3669 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3671 memset(ft_bitmap.buffer, 0, buflen);
3673 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3675 if(format == GGO_GRAY2_BITMAP)
3677 else if(format == GGO_GRAY4_BITMAP)
3679 else if(format == GGO_GRAY8_BITMAP)
3681 else if(format == WINE_GGO_GRAY16_BITMAP)
3689 for(row = 0; row < height; row++) {
3691 for(col = 0; col < width; col++, ptr++) {
3692 *ptr = (((int)*ptr) * mult + 128) / 256;
3701 int contour, point = 0, first_pt;
3702 FT_Outline *outline = &ft_face->glyph->outline;
3703 TTPOLYGONHEADER *pph;
3705 DWORD pph_start, cpfx, type;
3707 if(buflen == 0) buf = NULL;
3709 if (needsTransform && buf) {
3710 pFT_Outline_Transform(outline, &transMat);
3713 for(contour = 0; contour < outline->n_contours; contour++) {
3715 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3718 pph->dwType = TT_POLYGON_TYPE;
3719 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3721 needed += sizeof(*pph);
3723 while(point <= outline->contours[contour]) {
3724 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3725 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3726 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3730 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3733 } while(point <= outline->contours[contour] &&
3734 (outline->tags[point] & FT_Curve_Tag_On) ==
3735 (outline->tags[point-1] & FT_Curve_Tag_On));
3736 /* At the end of a contour Windows adds the start point, but
3738 if(point > outline->contours[contour] &&
3739 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3741 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3743 } else if(point <= outline->contours[contour] &&
3744 outline->tags[point] & FT_Curve_Tag_On) {
3745 /* add closing pt for bezier */
3747 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3755 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3758 pph->cb = needed - pph_start;
3764 /* Convert the quadratic Beziers to cubic Beziers.
3765 The parametric eqn for a cubic Bezier is, from PLRM:
3766 r(t) = at^3 + bt^2 + ct + r0
3767 with the control points:
3772 A quadratic Beizer has the form:
3773 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3775 So equating powers of t leads to:
3776 r1 = 2/3 p1 + 1/3 p0
3777 r2 = 2/3 p1 + 1/3 p2
3778 and of course r0 = p0, r3 = p2
3781 int contour, point = 0, first_pt;
3782 FT_Outline *outline = &ft_face->glyph->outline;
3783 TTPOLYGONHEADER *pph;
3785 DWORD pph_start, cpfx, type;
3786 FT_Vector cubic_control[4];
3787 if(buflen == 0) buf = NULL;
3789 if (needsTransform && buf) {
3790 pFT_Outline_Transform(outline, &transMat);
3793 for(contour = 0; contour < outline->n_contours; contour++) {
3795 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3798 pph->dwType = TT_POLYGON_TYPE;
3799 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3801 needed += sizeof(*pph);
3803 while(point <= outline->contours[contour]) {
3804 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3805 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3806 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3809 if(type == TT_PRIM_LINE) {
3811 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3815 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3818 /* FIXME: Possible optimization in endpoint calculation
3819 if there are two consecutive curves */
3820 cubic_control[0] = outline->points[point-1];
3821 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3822 cubic_control[0].x += outline->points[point].x + 1;
3823 cubic_control[0].y += outline->points[point].y + 1;
3824 cubic_control[0].x >>= 1;
3825 cubic_control[0].y >>= 1;
3827 if(point+1 > outline->contours[contour])
3828 cubic_control[3] = outline->points[first_pt];
3830 cubic_control[3] = outline->points[point+1];
3831 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3832 cubic_control[3].x += outline->points[point].x + 1;
3833 cubic_control[3].y += outline->points[point].y + 1;
3834 cubic_control[3].x >>= 1;
3835 cubic_control[3].y >>= 1;
3838 /* r1 = 1/3 p0 + 2/3 p1
3839 r2 = 1/3 p2 + 2/3 p1 */
3840 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3841 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3842 cubic_control[2] = cubic_control[1];
3843 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3844 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3845 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3846 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3848 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3849 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3850 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3855 } while(point <= outline->contours[contour] &&
3856 (outline->tags[point] & FT_Curve_Tag_On) ==
3857 (outline->tags[point-1] & FT_Curve_Tag_On));
3858 /* At the end of a contour Windows adds the start point,
3859 but only for Beziers and we've already done that.
3861 if(point <= outline->contours[contour] &&
3862 outline->tags[point] & FT_Curve_Tag_On) {
3863 /* This is the closing pt of a bezier, but we've already
3864 added it, so just inc point and carry on */
3871 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3874 pph->cb = needed - pph_start;
3880 FIXME("Unsupported format %d\n", format);
3886 static BOOL get_bitmap_text_metrics(GdiFont *font)
3888 FT_Face ft_face = font->ft_face;
3889 #ifdef HAVE_FREETYPE_FTWINFNT_H
3890 FT_WinFNT_HeaderRec winfnt_header;
3892 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3893 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3894 font->potm->otmSize = size;
3896 #define TM font->potm->otmTextMetrics
3897 #ifdef HAVE_FREETYPE_FTWINFNT_H
3898 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3900 TM.tmHeight = winfnt_header.pixel_height;
3901 TM.tmAscent = winfnt_header.ascent;
3902 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3903 TM.tmInternalLeading = winfnt_header.internal_leading;
3904 TM.tmExternalLeading = winfnt_header.external_leading;
3905 TM.tmAveCharWidth = winfnt_header.avg_width;
3906 TM.tmMaxCharWidth = winfnt_header.max_width;
3907 TM.tmWeight = winfnt_header.weight;
3909 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3910 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3911 TM.tmFirstChar = winfnt_header.first_char;
3912 TM.tmLastChar = winfnt_header.last_char;
3913 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3914 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3915 TM.tmItalic = winfnt_header.italic;
3916 TM.tmUnderlined = font->underline;
3917 TM.tmStruckOut = font->strikeout;
3918 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3919 TM.tmCharSet = winfnt_header.charset;
3924 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3925 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3926 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3927 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3928 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3929 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3930 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3931 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3933 TM.tmDigitizedAspectX = 96; /* FIXME */
3934 TM.tmDigitizedAspectY = 96; /* FIXME */
3936 TM.tmLastChar = 255;
3937 TM.tmDefaultChar = 32;
3938 TM.tmBreakChar = 32;
3939 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3940 TM.tmUnderlined = font->underline;
3941 TM.tmStruckOut = font->strikeout;
3942 /* NB inverted meaning of TMPF_FIXED_PITCH */
3943 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3944 TM.tmCharSet = font->charset;
3951 /*************************************************************
3952 * WineEngGetTextMetrics
3955 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3958 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3959 if(!get_bitmap_text_metrics(font))
3962 if(!font->potm) return FALSE;
3963 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3965 if (font->aveWidth) {
3966 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3972 /*************************************************************
3973 * WineEngGetOutlineTextMetrics
3976 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3977 OUTLINETEXTMETRICW *potm)
3979 FT_Face ft_face = font->ft_face;
3980 UINT needed, lenfam, lensty, ret;
3982 TT_HoriHeader *pHori;
3983 TT_Postscript *pPost;
3984 FT_Fixed x_scale, y_scale;
3985 WCHAR *family_nameW, *style_nameW;
3986 static const WCHAR spaceW[] = {' ', '\0'};
3988 INT ascent, descent;
3990 TRACE("font=%p\n", font);
3992 if(!FT_IS_SCALABLE(ft_face))
3996 if(cbSize >= font->potm->otmSize)
3997 memcpy(potm, font->potm, font->potm->otmSize);
3998 return font->potm->otmSize;
4002 needed = sizeof(*potm);
4004 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4005 family_nameW = strdupW(font->name);
4007 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4009 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4010 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4011 style_nameW, lensty/sizeof(WCHAR));
4013 /* These names should be read from the TT name table */
4015 /* length of otmpFamilyName */
4018 /* length of otmpFaceName */
4019 if(!strcasecmp(ft_face->style_name, "regular")) {
4020 needed += lenfam; /* just the family name */
4022 needed += lenfam + lensty; /* family + " " + style */
4025 /* length of otmpStyleName */
4028 /* length of otmpFullName */
4029 needed += lenfam + lensty;
4032 x_scale = ft_face->size->metrics.x_scale;
4033 y_scale = ft_face->size->metrics.y_scale;
4035 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4037 FIXME("Can't find OS/2 table - not TT font?\n");
4042 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4044 FIXME("Can't find HHEA table - not TT font?\n");
4049 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4051 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",
4052 pOS2->usWinAscent, pOS2->usWinDescent,
4053 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4054 ft_face->ascender, ft_face->descender, ft_face->height,
4055 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4056 ft_face->bbox.yMax, ft_face->bbox.yMin);
4058 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4059 font->potm->otmSize = needed;
4061 #define TM font->potm->otmTextMetrics
4063 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4064 ascent = pHori->Ascender;
4065 descent = -pHori->Descender;
4067 ascent = pOS2->usWinAscent;
4068 descent = pOS2->usWinDescent;
4072 TM.tmAscent = font->yMax;
4073 TM.tmDescent = -font->yMin;
4074 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4076 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4077 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4078 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4079 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4082 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4085 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4087 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4088 ((ascent + descent) -
4089 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4091 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4092 if (TM.tmAveCharWidth == 0) {
4093 TM.tmAveCharWidth = 1;
4095 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4096 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4098 TM.tmDigitizedAspectX = 300;
4099 TM.tmDigitizedAspectY = 300;
4100 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4101 * symbol range to 0 - f0ff
4103 if (font->charset == SYMBOL_CHARSET)
4106 TM.tmFirstChar = pOS2->usFirstCharIndex;
4107 TM.tmLastChar = pOS2->usLastCharIndex;
4108 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4109 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4110 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4111 TM.tmUnderlined = font->underline;
4112 TM.tmStruckOut = font->strikeout;
4114 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4115 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4116 (pOS2->version == 0xFFFFU ||
4117 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4118 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4120 TM.tmPitchAndFamily = 0;
4122 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4123 case PAN_FAMILY_SCRIPT:
4124 TM.tmPitchAndFamily |= FF_SCRIPT;
4126 case PAN_FAMILY_DECORATIVE:
4127 case PAN_FAMILY_PICTORIAL:
4128 TM.tmPitchAndFamily |= FF_DECORATIVE;
4130 case PAN_FAMILY_TEXT_DISPLAY:
4131 if(TM.tmPitchAndFamily == 0) /* fixed */
4132 TM.tmPitchAndFamily = FF_MODERN;
4134 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4135 case PAN_SERIF_NORMAL_SANS:
4136 case PAN_SERIF_OBTUSE_SANS:
4137 case PAN_SERIF_PERP_SANS:
4138 TM.tmPitchAndFamily |= FF_SWISS;
4141 TM.tmPitchAndFamily |= FF_ROMAN;
4146 TM.tmPitchAndFamily |= FF_DONTCARE;
4149 if(FT_IS_SCALABLE(ft_face))
4150 TM.tmPitchAndFamily |= TMPF_VECTOR;
4152 if(FT_IS_SFNT(ft_face))
4154 if (font->ntmFlags & NTM_PS_OPENTYPE)
4155 TM.tmPitchAndFamily |= TMPF_DEVICE;
4157 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4160 TM.tmCharSet = font->charset;
4163 font->potm->otmFiller = 0;
4164 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4165 font->potm->otmfsSelection = pOS2->fsSelection;
4166 font->potm->otmfsType = pOS2->fsType;
4167 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4168 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4169 font->potm->otmItalicAngle = 0; /* POST table */
4170 font->potm->otmEMSquare = ft_face->units_per_EM;
4171 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4172 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4173 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4174 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4175 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4176 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4177 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4178 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4179 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4180 font->potm->otmMacAscent = 0; /* where do these come from ? */
4181 font->potm->otmMacDescent = 0;
4182 font->potm->otmMacLineGap = 0;
4183 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4184 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4185 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4186 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4187 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4188 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4189 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4190 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4191 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4192 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4193 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4195 font->potm->otmsUnderscoreSize = 0;
4196 font->potm->otmsUnderscorePosition = 0;
4198 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4199 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4202 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4203 cp = (char*)font->potm + sizeof(*font->potm);
4204 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4205 strcpyW((WCHAR*)cp, family_nameW);
4207 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4208 strcpyW((WCHAR*)cp, style_nameW);
4210 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4211 strcpyW((WCHAR*)cp, family_nameW);
4212 if(strcasecmp(ft_face->style_name, "regular")) {
4213 strcatW((WCHAR*)cp, spaceW);
4214 strcatW((WCHAR*)cp, style_nameW);
4215 cp += lenfam + lensty;
4218 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4219 strcpyW((WCHAR*)cp, family_nameW);
4220 strcatW((WCHAR*)cp, spaceW);
4221 strcatW((WCHAR*)cp, style_nameW);
4224 if(potm && needed <= cbSize)
4225 memcpy(potm, font->potm, font->potm->otmSize);
4228 HeapFree(GetProcessHeap(), 0, style_nameW);
4229 HeapFree(GetProcessHeap(), 0, family_nameW);
4234 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4236 HFONTLIST *hfontlist;
4237 child->font = alloc_font();
4238 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
4239 if(!child->font->ft_face)
4241 free_font(child->font);
4246 child->font->ntmFlags = child->face->ntmFlags;
4247 child->font->orientation = font->orientation;
4248 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4249 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4250 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4251 child->font->base_font = font;
4252 list_add_head(&child_font_list, &child->font->entry);
4253 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4257 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4260 CHILD_FONT *child_font;
4263 font = font->base_font;
4265 *linked_font = font;
4267 if((*glyph = get_glyph_index(font, c)))
4270 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4272 if(!child_font->font)
4273 if(!load_child_font(font, child_font))
4276 if(!child_font->font->ft_face)
4278 g = get_glyph_index(child_font->font, c);
4282 *linked_font = child_font->font;
4289 /*************************************************************
4290 * WineEngGetCharWidth
4293 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4298 FT_UInt glyph_index;
4299 GdiFont *linked_font;
4301 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4303 for(c = firstChar; c <= lastChar; c++) {
4304 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4305 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4306 &gm, 0, NULL, NULL);
4307 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4312 /*************************************************************
4313 * WineEngGetCharABCWidths
4316 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4321 FT_UInt glyph_index;
4322 GdiFont *linked_font;
4324 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4326 if(!FT_IS_SCALABLE(font->ft_face))
4329 for(c = firstChar; c <= lastChar; c++) {
4330 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4331 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4332 &gm, 0, NULL, NULL);
4333 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4334 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4335 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4336 FONT_GM(linked_font,glyph_index)->bbx;
4341 /*************************************************************
4342 * WineEngGetCharABCWidthsI
4345 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4350 FT_UInt glyph_index;
4351 GdiFont *linked_font;
4353 if(!FT_IS_SCALABLE(font->ft_face))
4356 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4358 for(c = firstChar; c < firstChar+count; c++) {
4359 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4360 &gm, 0, NULL, NULL);
4361 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4362 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4363 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4364 - FONT_GM(linked_font,c)->bbx;
4367 for(c = 0; c < count; c++) {
4368 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4369 &gm, 0, NULL, NULL);
4370 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4371 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4372 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4373 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4379 /*************************************************************
4380 * WineEngGetTextExtentExPoint
4383 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4384 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4390 FT_UInt glyph_index;
4391 GdiFont *linked_font;
4393 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4397 WineEngGetTextMetrics(font, &tm);
4398 size->cy = tm.tmHeight;
4400 for(idx = 0; idx < count; idx++) {
4401 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4402 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4403 &gm, 0, NULL, NULL);
4404 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4406 if (! pnfit || ext <= max_ext) {
4416 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4420 /*************************************************************
4421 * WineEngGetTextExtentPointI
4424 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4431 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4434 WineEngGetTextMetrics(font, &tm);
4435 size->cy = tm.tmHeight;
4437 for(idx = 0; idx < count; idx++) {
4438 WineEngGetGlyphOutline(font, indices[idx],
4439 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4441 size->cx += FONT_GM(font,indices[idx])->adv;
4443 TRACE("return %d,%d\n", size->cx, size->cy);
4447 /*************************************************************
4448 * WineEngGetFontData
4451 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4454 FT_Face ft_face = font->ft_face;
4458 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4459 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4460 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4462 if(!FT_IS_SFNT(ft_face))
4470 if(table) { /* MS tags differ in endidness from FT ones */
4471 table = table >> 24 | table << 24 |
4472 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4475 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4476 if(pFT_Load_Sfnt_Table) {
4477 /* make sure value of len is the value freetype says it needs */
4479 FT_ULong needed = 0;
4480 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4481 if( !err && needed < len) len = needed;
4483 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4485 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4486 else { /* Do it the hard way */
4487 TT_Face tt_face = (TT_Face) ft_face;
4488 SFNT_Interface *sfnt;
4489 if (FT_Version.major==2 && FT_Version.minor==0)
4492 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4496 /* A field was added in the middle of the structure in 2.1.x */
4497 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4499 /* make sure value of len is the value freetype says it needs */
4501 FT_ULong needed = 0;
4502 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4503 if( !err && needed < len) len = needed;
4505 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4511 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4512 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4513 "Please upgrade your freetype library.\n");
4516 err = FT_Err_Unimplemented_Feature;
4520 TRACE("Can't find table %c%c%c%c\n",
4521 /* bytes were reversed */
4522 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4523 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4529 /*************************************************************
4530 * WineEngGetTextFace
4533 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4536 lstrcpynW(str, font->name, count);
4537 return strlenW(font->name);
4539 return strlenW(font->name) + 1;
4542 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4544 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4545 return font->charset;
4548 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4550 GdiFont *font = dc->gdiFont, *linked_font;
4551 struct list *first_hfont;
4554 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4555 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4556 if(font == linked_font)
4557 *new_hfont = dc->hFont;
4560 first_hfont = list_head(&linked_font->hfontlist);
4561 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4567 /* Retrieve a list of supported Unicode ranges for a given font.
4568 * Can be called with NULL gs to calculate the buffer size. Returns
4569 * the number of ranges found.
4571 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4573 DWORD num_ranges = 0;
4575 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4578 FT_ULong char_code, char_code_prev;
4581 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4583 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4584 face->num_glyphs, glyph_code, char_code);
4586 if (!glyph_code) return 0;
4590 gs->ranges[0].wcLow = (USHORT)char_code;
4591 gs->ranges[0].cGlyphs = 0;
4592 gs->cGlyphsSupported = 0;
4598 if (char_code < char_code_prev)
4600 ERR("expected increasing char code from FT_Get_Next_Char\n");
4603 if (char_code - char_code_prev > 1)
4608 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4609 gs->ranges[num_ranges - 1].cGlyphs = 1;
4610 gs->cGlyphsSupported++;
4615 gs->ranges[num_ranges - 1].cGlyphs++;
4616 gs->cGlyphsSupported++;
4618 char_code_prev = char_code;
4619 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4623 FIXME("encoding %u not supported\n", face->charmap->encoding);
4628 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
4631 DC *dc = DC_GetDCPtr(hdc);
4633 TRACE("(%p, %p)\n", hdc, glyphset);
4639 DWORD num_ranges = get_font_unicode_ranges(dc->gdiFont->ft_face, glyphset);
4641 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4644 glyphset->cbThis = size;
4645 glyphset->cRanges = num_ranges;
4649 DC_ReleaseDCPtr(dc);
4653 /*************************************************************
4656 BOOL WINAPI FontIsLinked(HDC hdc)
4658 DC *dc = DC_GetDCPtr(hdc);
4661 if(!dc) return FALSE;
4662 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4664 DC_ReleaseDCPtr(dc);
4665 TRACE("returning %d\n", ret);
4669 static BOOL is_hinting_enabled(void)
4671 /* Use the >= 2.2.0 function if available */
4672 if(pFT_Get_TrueType_Engine_Type)
4674 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4675 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4677 #ifdef FT_DRIVER_HAS_HINTER
4682 /* otherwise if we've been compiled with < 2.2.0 headers
4683 use the internal macro */
4684 mod = pFT_Get_Module(library, "truetype");
4685 if(mod && FT_DRIVER_HAS_HINTER(mod))
4693 /*************************************************************************
4694 * GetRasterizerCaps (GDI32.@)
4696 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4698 static int hinting = -1;
4702 hinting = is_hinting_enabled();
4703 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4706 lprs->nSize = sizeof(RASTERIZER_STATUS);
4707 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4708 lprs->nLanguageID = 0;
4712 /*************************************************************************
4713 * Kerning support for TrueType fonts
4715 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4717 struct TT_kern_table
4723 struct TT_kern_subtable
4732 USHORT horizontal : 1;
4734 USHORT cross_stream: 1;
4735 USHORT override : 1;
4736 USHORT reserved1 : 4;
4742 struct TT_format0_kern_subtable
4746 USHORT entrySelector;
4757 static DWORD parse_format0_kern_subtable(GdiFont *font,
4758 const struct TT_format0_kern_subtable *tt_f0_ks,
4759 const USHORT *glyph_to_char,
4760 KERNINGPAIR *kern_pair, DWORD cPairs)
4763 const struct TT_kern_pair *tt_kern_pair;
4765 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4767 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4769 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4770 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4771 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4773 if (!kern_pair || !cPairs)
4776 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4778 nPairs = min(nPairs, cPairs);
4780 for (i = 0; i < nPairs; i++)
4782 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4783 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4784 /* this algorithm appears to better match what Windows does */
4785 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4786 if (kern_pair->iKernAmount < 0)
4788 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4789 kern_pair->iKernAmount -= font->ppem;
4791 else if (kern_pair->iKernAmount > 0)
4793 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4794 kern_pair->iKernAmount += font->ppem;
4796 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4798 TRACE("left %u right %u value %d\n",
4799 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4803 TRACE("copied %u entries\n", nPairs);
4807 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4811 const struct TT_kern_table *tt_kern_table;
4812 const struct TT_kern_subtable *tt_kern_subtable;
4814 USHORT *glyph_to_char;
4816 if (font->total_kern_pairs != (DWORD)-1)
4818 if (cPairs && kern_pair)
4820 cPairs = min(cPairs, font->total_kern_pairs);
4821 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4824 return font->total_kern_pairs;
4827 font->total_kern_pairs = 0;
4829 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4831 if (length == GDI_ERROR)
4833 TRACE("no kerning data in the font\n");
4837 buf = HeapAlloc(GetProcessHeap(), 0, length);
4840 WARN("Out of memory\n");
4844 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4846 /* build a glyph index to char code map */
4847 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4850 WARN("Out of memory allocating a glyph index to char code map\n");
4851 HeapFree(GetProcessHeap(), 0, buf);
4855 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4861 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4863 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4864 font->ft_face->num_glyphs, glyph_code, char_code);
4868 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4870 /* FIXME: This doesn't match what Windows does: it does some fancy
4871 * things with duplicate glyph index to char code mappings, while
4872 * we just avoid overriding existing entries.
4874 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4875 glyph_to_char[glyph_code] = (USHORT)char_code;
4877 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4884 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4885 for (n = 0; n <= 65535; n++)
4886 glyph_to_char[n] = (USHORT)n;
4889 tt_kern_table = buf;
4890 nTables = GET_BE_WORD(tt_kern_table->nTables);
4891 TRACE("version %u, nTables %u\n",
4892 GET_BE_WORD(tt_kern_table->version), nTables);
4894 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4896 for (i = 0; i < nTables; i++)
4898 struct TT_kern_subtable tt_kern_subtable_copy;
4900 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4901 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4902 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4904 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4905 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4906 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4908 /* According to the TrueType specification this is the only format
4909 * that will be properly interpreted by Windows and OS/2
4911 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4913 DWORD new_chunk, old_total = font->total_kern_pairs;
4915 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4916 glyph_to_char, NULL, 0);
4917 font->total_kern_pairs += new_chunk;
4919 if (!font->kern_pairs)
4920 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4921 font->total_kern_pairs * sizeof(*font->kern_pairs));
4923 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4924 font->total_kern_pairs * sizeof(*font->kern_pairs));
4926 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4927 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4930 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4932 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4935 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4936 HeapFree(GetProcessHeap(), 0, buf);
4938 if (cPairs && kern_pair)
4940 cPairs = min(cPairs, font->total_kern_pairs);
4941 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4944 return font->total_kern_pairs;
4947 #else /* HAVE_FREETYPE */
4949 /*************************************************************************/
4951 BOOL WineEngInit(void)
4955 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4959 BOOL WineEngDestroyFontInstance(HFONT hfont)
4964 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4969 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4970 LPWORD pgi, DWORD flags)
4975 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4976 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4979 ERR("called but we don't have FreeType\n");
4983 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4985 ERR("called but we don't have FreeType\n");
4989 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4990 OUTLINETEXTMETRICW *potm)
4992 ERR("called but we don't have FreeType\n");
4996 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4999 ERR("called but we don't have FreeType\n");
5003 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5006 ERR("called but we don't have FreeType\n");
5010 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5013 ERR("called but we don't have FreeType\n");
5017 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5018 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5020 ERR("called but we don't have FreeType\n");
5024 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
5027 ERR("called but we don't have FreeType\n");
5031 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5034 ERR("called but we don't have FreeType\n");
5038 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5040 ERR("called but we don't have FreeType\n");
5044 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5050 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5056 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5062 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5065 return DEFAULT_CHARSET;
5068 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5073 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
5075 FIXME("(%p, %p): stub\n", hdc, glyphset);
5079 BOOL WINAPI FontIsLinked(HDC hdc)
5084 /*************************************************************************
5085 * GetRasterizerCaps (GDI32.@)
5087 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5089 lprs->nSize = sizeof(RASTERIZER_STATUS);
5091 lprs->nLanguageID = 0;
5095 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5097 ERR("called but we don't have FreeType\n");
5101 #endif /* HAVE_FREETYPE */