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>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FT2BUILD_H
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
120 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
121 #include <freetype/internal/sfnt.h>
123 #ifdef HAVE_FREETYPE_FTTRIGON_H
124 #include <freetype/fttrigon.h>
126 #ifdef HAVE_FREETYPE_FTWINFNT_H
127 #include <freetype/ftwinfnt.h>
129 #ifdef HAVE_FREETYPE_FTMODAPI_H
130 #include <freetype/ftmodapi.h>
132 #ifdef HAVE_FREETYPE_FTLCDFIL_H
133 #include <freetype/ftlcdfil.h>
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
139 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType;
145 static FT_Library library = 0;
152 static FT_Version_t FT_Version;
153 static DWORD FT_SimpleVersion;
155 static void *ft_handle = NULL;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Vector_Unit);
159 MAKE_FUNCPTR(FT_Done_Face);
160 MAKE_FUNCPTR(FT_Get_Char_Index);
161 MAKE_FUNCPTR(FT_Get_Module);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Init_FreeType);
166 MAKE_FUNCPTR(FT_Load_Glyph);
167 MAKE_FUNCPTR(FT_Matrix_Multiply);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
171 MAKE_FUNCPTR(FT_MulFix);
173 MAKE_FUNCPTR(FT_New_Face);
174 MAKE_FUNCPTR(FT_New_Memory_Face);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
176 MAKE_FUNCPTR(FT_Outline_Transform);
177 MAKE_FUNCPTR(FT_Outline_Translate);
178 MAKE_FUNCPTR(FT_Select_Charmap);
179 MAKE_FUNCPTR(FT_Set_Charmap);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
181 MAKE_FUNCPTR(FT_Vector_Transform);
182 MAKE_FUNCPTR(FT_Render_Glyph);
183 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
184 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
185 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
186 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
191 #ifdef HAVE_FREETYPE_FTWINFNT_H
192 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
195 #ifdef SONAME_LIBFONTCONFIG
196 #include <fontconfig/fontconfig.h>
197 MAKE_FUNCPTR(FcConfigGetCurrent);
198 MAKE_FUNCPTR(FcFontList);
199 MAKE_FUNCPTR(FcFontSetDestroy);
200 MAKE_FUNCPTR(FcInit);
201 MAKE_FUNCPTR(FcObjectSetAdd);
202 MAKE_FUNCPTR(FcObjectSetCreate);
203 MAKE_FUNCPTR(FcObjectSetDestroy);
204 MAKE_FUNCPTR(FcPatternCreate);
205 MAKE_FUNCPTR(FcPatternDestroy);
206 MAKE_FUNCPTR(FcPatternGetBool);
207 MAKE_FUNCPTR(FcPatternGetString);
213 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
214 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
215 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
218 #ifndef ft_encoding_none
219 #define FT_ENCODING_NONE ft_encoding_none
221 #ifndef ft_encoding_ms_symbol
222 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
224 #ifndef ft_encoding_unicode
225 #define FT_ENCODING_UNICODE ft_encoding_unicode
227 #ifndef ft_encoding_apple_roman
228 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
231 #ifdef WORDS_BIGENDIAN
232 #define GET_BE_WORD(x) (x)
234 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
237 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
244 FT_Short internal_leading;
247 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
248 So to let this compile on older versions of FreeType we'll define the
249 new structure here. */
251 FT_Short height, width;
252 FT_Pos size, x_ppem, y_ppem;
258 NEWTEXTMETRICEXW ntm;
262 typedef struct tagFace {
267 DWORD font_data_size;
270 FONTSIGNATURE fs_links;
272 FT_Fixed font_version;
274 Bitmap_Size size; /* set if face is a bitmap */
275 BOOL external; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily *family;
277 /* Cached data for Enum */
278 struct enum_data *cached_enum_data;
281 typedef struct tagFamily {
283 const WCHAR *FamilyName;
289 INT adv; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST {
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping *mapping;
353 const WCHAR *font_name;
357 struct enum_charset_element {
363 struct enum_charset_list {
365 struct enum_charset_element element[32];
368 #define GM_BLOCK_SIZE 128
369 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
371 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
372 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
373 #define UNUSED_CACHE_SIZE 10
374 static struct list child_font_list = LIST_INIT(child_font_list);
375 static struct list system_links = LIST_INIT(system_links);
377 static struct list font_subst_list = LIST_INIT(font_subst_list);
379 static struct list font_list = LIST_INIT(font_list);
381 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
382 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
383 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
385 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
386 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
387 'W','i','n','d','o','w','s','\\',
388 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
389 'F','o','n','t','s','\0'};
391 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
392 'W','i','n','d','o','w','s',' ','N','T','\\',
393 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
394 'F','o','n','t','s','\0'};
396 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
397 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
398 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
399 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
401 static const WCHAR * const SystemFontValues[4] = {
408 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
409 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
411 /* Interesting and well-known (frequently-assumed!) font names */
412 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
413 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
414 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
415 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
416 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
417 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
418 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
419 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
421 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
422 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
423 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
424 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
425 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
426 'E','u','r','o','p','e','a','n','\0'};
427 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
428 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
429 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
430 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
431 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
432 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
433 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
434 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
435 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
436 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
437 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
438 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
440 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
450 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
458 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
467 typedef struct tagFontSubst {
483 static struct list mappings_list = LIST_INIT( mappings_list );
485 static CRITICAL_SECTION freetype_cs;
486 static CRITICAL_SECTION_DEBUG critsect_debug =
489 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
490 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
492 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
494 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
496 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
497 static BOOL use_default_fallback = FALSE;
499 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
501 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
502 'W','i','n','d','o','w','s',' ','N','T','\\',
503 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
504 'S','y','s','t','e','m','L','i','n','k',0};
506 /****************************************
507 * Notes on .fon files
509 * The fonts System, FixedSys and Terminal are special. There are typically multiple
510 * versions installed for different resolutions and codepages. Windows stores which one to use
511 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
513 * FIXEDFON.FON FixedSys
515 * OEMFONT.FON Terminal
516 * LogPixels Current dpi set by the display control panel applet
517 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
518 * also has a LogPixels value that appears to mirror this)
520 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
521 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
522 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
523 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
524 * so that makes sense.
526 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
527 * to be mapped into the registry on Windows 2000 at least).
530 * ega80woa.fon=ega80850.fon
531 * ega40woa.fon=ega40850.fon
532 * cga80woa.fon=cga80850.fon
533 * cga40woa.fon=cga40850.fon
536 /* These are all structures needed for the GSUB table */
538 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
539 #define TATEGAKI_LOWER_BOUND 0x02F1
555 GSUB_ScriptRecord ScriptRecord[1];
561 } GSUB_LangSysRecord;
566 GSUB_LangSysRecord LangSysRecord[1];
570 WORD LookupOrder; /* Reserved */
571 WORD ReqFeatureIndex;
573 WORD FeatureIndex[1];
579 } GSUB_FeatureRecord;
583 GSUB_FeatureRecord FeatureRecord[1];
587 WORD FeatureParams; /* Reserved */
589 WORD LookupListIndex[1];
608 } GSUB_CoverageFormat1;
613 WORD StartCoverageIndex;
619 GSUB_RangeRecord RangeRecord[1];
620 } GSUB_CoverageFormat2;
623 WORD SubstFormat; /* = 1 */
626 } GSUB_SingleSubstFormat1;
629 WORD SubstFormat; /* = 2 */
633 }GSUB_SingleSubstFormat2;
635 #ifdef HAVE_CARBON_CARBON_H
636 static char *find_cache_dir(void)
640 static char cached_path[MAX_PATH];
641 static const char *wine = "/Wine", *fonts = "/Fonts";
643 if(*cached_path) return cached_path;
645 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
648 WARN("can't create cached data folder\n");
651 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
654 WARN("can't create cached data path\n");
658 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
660 ERR("Could not create full path\n");
664 strcat(cached_path, wine);
666 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
668 WARN("Couldn't mkdir %s\n", cached_path);
672 strcat(cached_path, fonts);
673 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
675 WARN("Couldn't mkdir %s\n", cached_path);
682 /******************************************************************
685 * Extracts individual TrueType font files from a Mac suitcase font
686 * and saves them into the user's caches directory (see
688 * Returns a NULL terminated array of filenames.
690 * We do this because they are apps that try to read ttf files
691 * themselves and they don't like Mac suitcase files.
693 static char **expand_mac_font(const char *path)
700 const char *filename;
704 unsigned int size, max_size;
707 TRACE("path %s\n", path);
709 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
712 WARN("failed to get ref\n");
716 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
719 TRACE("no data fork, so trying resource fork\n");
720 res_ref = FSOpenResFile(&ref, fsRdPerm);
723 TRACE("unable to open resource fork\n");
730 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
733 CloseResFile(res_ref);
737 out_dir = find_cache_dir();
739 filename = strrchr(path, '/');
740 if(!filename) filename = path;
743 /* output filename has the form out_dir/filename_%04x.ttf */
744 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
751 unsigned short *num_faces_ptr, num_faces, face;
754 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
756 fond = Get1IndResource(fond_res, idx);
758 TRACE("got fond resource %d\n", idx);
761 fam_rec = *(FamRec**)fond;
762 num_faces_ptr = (unsigned short *)(fam_rec + 1);
763 num_faces = GET_BE_WORD(*num_faces_ptr);
765 assoc = (AsscEntry*)(num_faces_ptr + 1);
766 TRACE("num faces %04x\n", num_faces);
767 for(face = 0; face < num_faces; face++, assoc++)
770 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
771 unsigned short size, font_id;
774 size = GET_BE_WORD(assoc->fontSize);
775 font_id = GET_BE_WORD(assoc->fontID);
778 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
782 TRACE("trying to load sfnt id %04x\n", font_id);
783 sfnt = GetResource(sfnt_res, font_id);
786 TRACE("can't get sfnt resource %04x\n", font_id);
790 output = HeapAlloc(GetProcessHeap(), 0, output_len);
795 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
797 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
798 if(fd != -1 || errno == EEXIST)
802 unsigned char *sfnt_data;
805 sfnt_data = *(unsigned char**)sfnt;
806 write(fd, sfnt_data, GetHandleSize(sfnt));
810 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
813 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
815 ret.array[ret.size++] = output;
819 WARN("unable to create %s\n", output);
820 HeapFree(GetProcessHeap(), 0, output);
823 ReleaseResource(sfnt);
826 ReleaseResource(fond);
829 CloseResFile(res_ref);
834 #endif /* HAVE_CARBON_CARBON_H */
836 static inline BOOL is_win9x(void)
838 return GetVersion() & 0x80000000;
841 This function builds an FT_Fixed from a double. It fails if the absolute
842 value of the float number is greater than 32768.
844 static inline FT_Fixed FT_FixedFromFloat(double f)
850 This function builds an FT_Fixed from a FIXED. It simply put f.value
851 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
853 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
855 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
859 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
864 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
865 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
867 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
868 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
870 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
872 if(face_name && strcmpiW(face_name, family->FamilyName))
874 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
878 file = strrchr(face->file, '/');
883 if(!strcasecmp(file, file_nameA))
885 HeapFree(GetProcessHeap(), 0, file_nameA);
890 HeapFree(GetProcessHeap(), 0, file_nameA);
894 static Family *find_family_from_name(const WCHAR *name)
898 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
900 if(!strcmpiW(family->FamilyName, name))
907 static void DumpSubstList(void)
911 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
913 if(psub->from.charset != -1 || psub->to.charset != -1)
914 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
915 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
917 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
918 debugstr_w(psub->to.name));
923 static LPWSTR strdupW(LPCWSTR p)
926 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
927 ret = HeapAlloc(GetProcessHeap(), 0, len);
932 static LPSTR strdupA(LPCSTR p)
935 DWORD len = (strlen(p) + 1);
936 ret = HeapAlloc(GetProcessHeap(), 0, len);
941 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
946 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
948 if(!strcmpiW(element->from.name, from_name) &&
949 (element->from.charset == from_charset ||
950 element->from.charset == -1))
957 #define ADD_FONT_SUBST_FORCE 1
959 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
961 FontSubst *from_exist, *to_exist;
963 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
965 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
967 list_remove(&from_exist->entry);
968 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
969 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
970 HeapFree(GetProcessHeap(), 0, from_exist);
976 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
980 HeapFree(GetProcessHeap(), 0, subst->to.name);
981 subst->to.name = strdupW(to_exist->to.name);
984 list_add_tail(subst_list, &subst->entry);
989 HeapFree(GetProcessHeap(), 0, subst->from.name);
990 HeapFree(GetProcessHeap(), 0, subst->to.name);
991 HeapFree(GetProcessHeap(), 0, subst);
995 static void split_subst_info(NameCs *nc, LPSTR str)
997 CHAR *p = strrchr(str, ',');
1002 nc->charset = strtol(p+1, NULL, 10);
1005 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1006 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1007 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1010 static void LoadSubstList(void)
1014 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1018 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1019 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1020 &hkey) == ERROR_SUCCESS) {
1022 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1023 &valuelen, &datalen, NULL, NULL);
1025 valuelen++; /* returned value doesn't include room for '\0' */
1026 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1027 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1031 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1032 &dlen) == ERROR_SUCCESS) {
1033 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1035 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1036 split_subst_info(&psub->from, value);
1037 split_subst_info(&psub->to, data);
1039 /* Win 2000 doesn't allow mapping between different charsets
1040 or mapping of DEFAULT_CHARSET */
1041 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1042 psub->to.charset == DEFAULT_CHARSET) {
1043 HeapFree(GetProcessHeap(), 0, psub->to.name);
1044 HeapFree(GetProcessHeap(), 0, psub->from.name);
1045 HeapFree(GetProcessHeap(), 0, psub);
1047 add_font_subst(&font_subst_list, psub, 0);
1049 /* reset dlen and vlen */
1053 HeapFree(GetProcessHeap(), 0, data);
1054 HeapFree(GetProcessHeap(), 0, value);
1060 /*****************************************************************
1061 * get_name_table_entry
1063 * Supply the platform, encoding, language and name ids in req
1064 * and if the name exists the function will fill in the string
1065 * and string_len members. The string is owned by FreeType so
1066 * don't free it. Returns TRUE if the name is found else FALSE.
1068 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1071 FT_UInt num_names, name_index;
1073 if(FT_IS_SFNT(ft_face))
1075 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1077 for(name_index = 0; name_index < num_names; name_index++)
1079 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1081 if((name.platform_id == req->platform_id) &&
1082 (name.encoding_id == req->encoding_id) &&
1083 (name.language_id == req->language_id) &&
1084 (name.name_id == req->name_id))
1086 req->string = name.string;
1087 req->string_len = name.string_len;
1094 req->string_len = 0;
1098 static WCHAR *get_familyname(FT_Face ft_face)
1100 WCHAR *family = NULL;
1103 name.platform_id = TT_PLATFORM_MICROSOFT;
1104 name.encoding_id = TT_MS_ID_UNICODE_CS;
1105 name.language_id = GetUserDefaultLCID();
1106 name.name_id = TT_NAME_ID_FONT_FAMILY;
1108 if(get_name_table_entry(ft_face, &name))
1112 /* String is not nul terminated and string_len is a byte length. */
1113 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1114 for(i = 0; i < name.string_len / 2; i++)
1116 WORD *tmp = (WORD *)&name.string[i * 2];
1117 family[i] = GET_BE_WORD(*tmp);
1120 TRACE("Got localised name %s\n", debugstr_w(family));
1127 /*****************************************************************
1130 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1131 * of FreeType that don't export this function.
1134 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1139 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1140 if(pFT_Load_Sfnt_Table)
1142 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1144 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1145 else /* Do it the hard way */
1147 TT_Face tt_face = (TT_Face) ft_face;
1148 SFNT_Interface *sfnt;
1149 if (FT_Version.major==2 && FT_Version.minor==0)
1152 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1156 /* A field was added in the middle of the structure in 2.1.x */
1157 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1159 err = sfnt->load_any(tt_face, table, offset, buf, len);
1167 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1168 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1169 "Please upgrade your freetype library.\n");
1172 err = FT_Err_Unimplemented_Feature;
1178 static inline int TestStyles(DWORD flags, DWORD styles)
1180 return (flags & styles) == styles;
1183 static int StyleOrdering(Face *face)
1185 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1187 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1189 if (TestStyles(face->ntmFlags, NTM_BOLD))
1191 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1194 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1195 debugstr_w(face->family->FamilyName),
1196 debugstr_w(face->StyleName),
1202 /* Add a style of face to a font family using an ordering of the list such
1203 that regular fonts come before bold and italic, and single styles come
1204 before compound styles. */
1205 static void AddFaceToFamily(Face *face, Family *family)
1209 LIST_FOR_EACH( entry, &family->faces )
1211 Face *ent = LIST_ENTRY(entry, Face, entry);
1212 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1214 list_add_before( entry, &face->entry );
1217 #define ADDFONT_EXTERNAL_FONT 0x01
1218 #define ADDFONT_FORCE_BITMAP 0x02
1219 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1223 TT_Header *pHeader = NULL;
1224 WCHAR *english_family, *localised_family, *StyleW;
1228 struct list *family_elem_ptr, *face_elem_ptr;
1230 FT_Long face_index = 0, num_faces;
1231 #ifdef HAVE_FREETYPE_FTWINFNT_H
1232 FT_WinFNT_HeaderRec winfnt_header;
1234 int i, bitmap_num, internal_leading;
1237 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1238 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1240 #ifdef HAVE_CARBON_CARBON_H
1241 if(file && !fake_family)
1243 char **mac_list = expand_mac_font(file);
1246 BOOL had_one = FALSE;
1248 for(cursor = mac_list; *cursor; cursor++)
1251 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1252 HeapFree(GetProcessHeap(), 0, *cursor);
1254 HeapFree(GetProcessHeap(), 0, mac_list);
1259 #endif /* HAVE_CARBON_CARBON_H */
1262 char *family_name = fake_family;
1266 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1267 err = pFT_New_Face(library, file, face_index, &ft_face);
1270 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1271 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1275 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1279 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*/
1280 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1281 pFT_Done_Face(ft_face);
1285 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1286 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1287 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1288 pFT_Done_Face(ft_face);
1292 if(FT_IS_SFNT(ft_face))
1294 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1295 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1296 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1298 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1299 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1300 pFT_Done_Face(ft_face);
1304 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1305 we don't want to load these. */
1306 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1310 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1312 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1313 pFT_Done_Face(ft_face);
1319 if(!ft_face->family_name || !ft_face->style_name) {
1320 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1321 pFT_Done_Face(ft_face);
1325 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1327 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1328 pFT_Done_Face(ft_face);
1334 localised_family = get_familyname(ft_face);
1335 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1337 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1338 HeapFree(GetProcessHeap(), 0, localised_family);
1339 num_faces = ft_face->num_faces;
1340 pFT_Done_Face(ft_face);
1343 HeapFree(GetProcessHeap(), 0, localised_family);
1347 family_name = ft_face->family_name;
1351 My_FT_Bitmap_Size *size = NULL;
1354 if(!FT_IS_SCALABLE(ft_face))
1355 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1357 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1358 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1359 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1361 localised_family = NULL;
1363 localised_family = get_familyname(ft_face);
1364 if(localised_family && !strcmpiW(localised_family, english_family)) {
1365 HeapFree(GetProcessHeap(), 0, localised_family);
1366 localised_family = NULL;
1371 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1372 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1373 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1378 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1379 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1380 list_init(&family->faces);
1381 list_add_tail(&font_list, &family->entry);
1383 if(localised_family) {
1384 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1385 subst->from.name = strdupW(english_family);
1386 subst->from.charset = -1;
1387 subst->to.name = strdupW(localised_family);
1388 subst->to.charset = -1;
1389 add_font_subst(&font_subst_list, subst, 0);
1392 HeapFree(GetProcessHeap(), 0, localised_family);
1393 HeapFree(GetProcessHeap(), 0, english_family);
1395 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1396 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1397 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1399 internal_leading = 0;
1400 memset(&fs, 0, sizeof(fs));
1402 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1404 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1405 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1406 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1407 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1408 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1409 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1410 if(pOS2->version == 0) {
1413 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1414 fs.fsCsb[0] |= FS_LATIN1;
1416 fs.fsCsb[0] |= FS_SYMBOL;
1419 #ifdef HAVE_FREETYPE_FTWINFNT_H
1420 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1422 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1423 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1424 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1426 internal_leading = winfnt_header.internal_leading;
1430 face_elem_ptr = list_head(&family->faces);
1431 while(face_elem_ptr) {
1432 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1433 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1434 if(!strcmpiW(face->StyleName, StyleW) &&
1435 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1436 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1437 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1438 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1441 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1442 HeapFree(GetProcessHeap(), 0, StyleW);
1443 pFT_Done_Face(ft_face);
1446 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1447 TRACE("Original font is newer so skipping this one\n");
1448 HeapFree(GetProcessHeap(), 0, StyleW);
1449 pFT_Done_Face(ft_face);
1452 TRACE("Replacing original with this one\n");
1453 list_remove(&face->entry);
1454 HeapFree(GetProcessHeap(), 0, face->file);
1455 HeapFree(GetProcessHeap(), 0, face->StyleName);
1456 HeapFree(GetProcessHeap(), 0, face);
1461 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1462 face->cached_enum_data = NULL;
1463 face->StyleName = StyleW;
1466 face->file = strdupA(file);
1467 face->font_data_ptr = NULL;
1468 face->font_data_size = 0;
1473 face->font_data_ptr = font_data_ptr;
1474 face->font_data_size = font_data_size;
1476 face->face_index = face_index;
1478 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1479 face->ntmFlags |= NTM_ITALIC;
1480 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1481 face->ntmFlags |= NTM_BOLD;
1482 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1483 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1484 face->family = family;
1485 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1487 memset(&face->fs_links, 0, sizeof(face->fs_links));
1489 if(FT_IS_SCALABLE(ft_face)) {
1490 memset(&face->size, 0, sizeof(face->size));
1491 face->scalable = TRUE;
1493 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1494 size->height, size->width, size->size >> 6,
1495 size->x_ppem >> 6, size->y_ppem >> 6);
1496 face->size.height = size->height;
1497 face->size.width = size->width;
1498 face->size.size = size->size;
1499 face->size.x_ppem = size->x_ppem;
1500 face->size.y_ppem = size->y_ppem;
1501 face->size.internal_leading = internal_leading;
1502 face->scalable = FALSE;
1505 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1507 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1509 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1510 face->ntmFlags |= NTM_PS_OPENTYPE;
1513 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1514 face->fs.fsCsb[0], face->fs.fsCsb[1],
1515 face->fs.fsUsb[0], face->fs.fsUsb[1],
1516 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1519 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1520 for(i = 0; i < ft_face->num_charmaps; i++) {
1521 switch(ft_face->charmaps[i]->encoding) {
1522 case FT_ENCODING_UNICODE:
1523 case FT_ENCODING_APPLE_ROMAN:
1524 face->fs.fsCsb[0] |= FS_LATIN1;
1526 case FT_ENCODING_MS_SYMBOL:
1527 face->fs.fsCsb[0] |= FS_SYMBOL;
1535 AddFaceToFamily(face, family);
1537 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1539 num_faces = ft_face->num_faces;
1540 pFT_Done_Face(ft_face);
1541 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1542 debugstr_w(StyleW));
1543 } while(num_faces > ++face_index);
1547 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1549 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1552 static void DumpFontList(void)
1556 struct list *family_elem_ptr, *face_elem_ptr;
1558 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1559 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1560 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1561 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1562 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1563 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1565 TRACE(" %d", face->size.height);
1572 /***********************************************************
1573 * The replacement list is a way to map an entire font
1574 * family onto another family. For example adding
1576 * [HKCU\Software\Wine\Fonts\Replacements]
1577 * "Wingdings"="Winedings"
1579 * would enumerate the Winedings font both as Winedings and
1580 * Wingdings. However if a real Wingdings font is present the
1581 * replacement does not take place.
1584 static void LoadReplaceList(void)
1587 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1592 struct list *family_elem_ptr, *face_elem_ptr;
1595 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1596 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1598 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1599 &valuelen, &datalen, NULL, NULL);
1601 valuelen++; /* returned value doesn't include room for '\0' */
1602 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1603 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1607 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1608 &dlen) == ERROR_SUCCESS) {
1609 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1610 /* "NewName"="Oldname" */
1611 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1613 /* Find the old family and hence all of the font files
1615 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1616 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1617 if(!strcmpiW(family->FamilyName, data)) {
1618 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1619 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1620 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1621 debugstr_w(face->StyleName), familyA);
1622 /* Now add a new entry with the new family name */
1623 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1628 /* reset dlen and vlen */
1632 HeapFree(GetProcessHeap(), 0, data);
1633 HeapFree(GetProcessHeap(), 0, value);
1638 /*************************************************************
1641 static BOOL init_system_links(void)
1645 DWORD type, max_val, max_data, val_len, data_len, index;
1646 WCHAR *value, *data;
1647 WCHAR *entry, *next;
1648 SYSTEM_LINKS *font_link, *system_font_link;
1649 CHILD_FONT *child_font;
1650 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1651 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1657 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1659 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1660 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1661 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1662 val_len = max_val + 1;
1663 data_len = max_data;
1665 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1667 memset(&fs, 0, sizeof(fs));
1668 psub = get_font_subst(&font_subst_list, value, -1);
1669 /* Don't store fonts that are only substitutes for other fonts */
1672 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1675 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1676 font_link->font_name = strdupW(value);
1677 list_init(&font_link->links);
1678 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1681 CHILD_FONT *child_font;
1683 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1685 next = entry + strlenW(entry) + 1;
1687 face_name = strchrW(entry, ',');
1691 while(isspaceW(*face_name))
1694 psub = get_font_subst(&font_subst_list, face_name, -1);
1696 face_name = psub->to.name;
1698 face = find_face_from_filename(entry, face_name);
1701 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1705 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1706 child_font->face = face;
1707 child_font->font = NULL;
1708 fs.fsCsb[0] |= face->fs.fsCsb[0];
1709 fs.fsCsb[1] |= face->fs.fsCsb[1];
1710 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1711 list_add_tail(&font_link->links, &child_font->entry);
1713 family = find_family_from_name(font_link->font_name);
1716 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1718 face->fs_links = fs;
1721 list_add_tail(&system_links, &font_link->entry);
1723 val_len = max_val + 1;
1724 data_len = max_data;
1727 HeapFree(GetProcessHeap(), 0, value);
1728 HeapFree(GetProcessHeap(), 0, data);
1732 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1735 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1736 system_font_link->font_name = strdupW(System);
1737 list_init(&system_font_link->links);
1739 face = find_face_from_filename(tahoma_ttf, Tahoma);
1742 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1743 child_font->face = face;
1744 child_font->font = NULL;
1745 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1746 list_add_tail(&system_font_link->links, &child_font->entry);
1748 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1750 if(!strcmpiW(font_link->font_name, Tahoma))
1752 CHILD_FONT *font_link_entry;
1753 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1755 CHILD_FONT *new_child;
1756 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1757 new_child->face = font_link_entry->face;
1758 new_child->font = NULL;
1759 list_add_tail(&system_font_link->links, &new_child->entry);
1764 list_add_tail(&system_links, &system_font_link->entry);
1768 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1771 struct dirent *dent;
1772 char path[MAX_PATH];
1774 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1776 dir = opendir(dirname);
1778 WARN("Can't open directory %s\n", debugstr_a(dirname));
1781 while((dent = readdir(dir)) != NULL) {
1782 struct stat statbuf;
1784 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1787 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1789 sprintf(path, "%s/%s", dirname, dent->d_name);
1791 if(stat(path, &statbuf) == -1)
1793 WARN("Can't stat %s\n", debugstr_a(path));
1796 if(S_ISDIR(statbuf.st_mode))
1797 ReadFontDir(path, external_fonts);
1799 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1805 static void load_fontconfig_fonts(void)
1807 #ifdef SONAME_LIBFONTCONFIG
1808 void *fc_handle = NULL;
1817 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1819 TRACE("Wine cannot find the fontconfig library (%s).\n",
1820 SONAME_LIBFONTCONFIG);
1823 #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;}
1824 LOAD_FUNCPTR(FcConfigGetCurrent);
1825 LOAD_FUNCPTR(FcFontList);
1826 LOAD_FUNCPTR(FcFontSetDestroy);
1827 LOAD_FUNCPTR(FcInit);
1828 LOAD_FUNCPTR(FcObjectSetAdd);
1829 LOAD_FUNCPTR(FcObjectSetCreate);
1830 LOAD_FUNCPTR(FcObjectSetDestroy);
1831 LOAD_FUNCPTR(FcPatternCreate);
1832 LOAD_FUNCPTR(FcPatternDestroy);
1833 LOAD_FUNCPTR(FcPatternGetBool);
1834 LOAD_FUNCPTR(FcPatternGetString);
1837 if(!pFcInit()) return;
1839 config = pFcConfigGetCurrent();
1840 pat = pFcPatternCreate();
1841 os = pFcObjectSetCreate();
1842 pFcObjectSetAdd(os, FC_FILE);
1843 pFcObjectSetAdd(os, FC_SCALABLE);
1844 fontset = pFcFontList(config, pat, os);
1845 if(!fontset) return;
1846 for(i = 0; i < fontset->nfont; i++) {
1849 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1851 TRACE("fontconfig: %s\n", file);
1853 /* We're just interested in OT/TT fonts for now, so this hack just
1854 picks up the scalable fonts without extensions .pf[ab] to save time
1855 loading every other font */
1857 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1859 TRACE("not scalable\n");
1863 len = strlen( file );
1864 if(len < 4) continue;
1865 ext = &file[ len - 3 ];
1866 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1867 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1869 pFcFontSetDestroy(fontset);
1870 pFcObjectSetDestroy(os);
1871 pFcPatternDestroy(pat);
1877 static BOOL load_font_from_data_dir(LPCWSTR file)
1880 const char *data_dir = wine_get_data_dir();
1882 if (!data_dir) data_dir = wine_get_build_dir();
1889 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1891 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1893 strcpy(unix_name, data_dir);
1894 strcat(unix_name, "/fonts/");
1896 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1898 EnterCriticalSection( &freetype_cs );
1899 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1900 LeaveCriticalSection( &freetype_cs );
1901 HeapFree(GetProcessHeap(), 0, unix_name);
1906 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1908 static const WCHAR slashW[] = {'\\','\0'};
1910 WCHAR windowsdir[MAX_PATH];
1913 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1914 strcatW(windowsdir, fontsW);
1915 strcatW(windowsdir, slashW);
1916 strcatW(windowsdir, file);
1917 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1918 EnterCriticalSection( &freetype_cs );
1919 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1920 LeaveCriticalSection( &freetype_cs );
1921 HeapFree(GetProcessHeap(), 0, unixname);
1926 static void load_system_fonts(void)
1929 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1930 const WCHAR * const *value;
1932 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1935 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1936 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1937 strcatW(windowsdir, fontsW);
1938 for(value = SystemFontValues; *value; value++) {
1939 dlen = sizeof(data);
1940 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1944 sprintfW(pathW, fmtW, windowsdir, data);
1945 if((unixname = wine_get_unix_file_name(pathW))) {
1946 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1947 HeapFree(GetProcessHeap(), 0, unixname);
1950 load_font_from_data_dir(data);
1957 /*************************************************************
1959 * This adds registry entries for any externally loaded fonts
1960 * (fonts from fontconfig or FontDirs). It also deletes entries
1961 * of no longer existing fonts.
1964 static void update_reg_entries(void)
1966 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1971 struct list *family_elem_ptr, *face_elem_ptr;
1973 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1974 static const WCHAR spaceW[] = {' ', '\0'};
1977 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1978 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1979 ERR("Can't create Windows font reg key\n");
1983 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1984 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1985 ERR("Can't create Windows font reg key\n");
1989 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1990 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1991 ERR("Can't create external font reg key\n");
1995 /* enumerate the fonts and add external ones to the two keys */
1997 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1998 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1999 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2000 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2001 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2002 if(!face->external) continue;
2004 if (!(face->ntmFlags & NTM_REGULAR))
2005 len = len_fam + strlenW(face->StyleName) + 1;
2006 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2007 strcpyW(valueW, family->FamilyName);
2008 if(len != len_fam) {
2009 strcatW(valueW, spaceW);
2010 strcatW(valueW, face->StyleName);
2012 strcatW(valueW, TrueType);
2014 file = wine_get_dos_file_name(face->file);
2016 len = strlenW(file) + 1;
2019 if((path = strrchr(face->file, '/')) == NULL)
2023 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2025 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2026 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2028 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2029 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2030 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2032 HeapFree(GetProcessHeap(), 0, file);
2033 HeapFree(GetProcessHeap(), 0, valueW);
2037 if(external_key) RegCloseKey(external_key);
2038 if(win9x_key) RegCloseKey(win9x_key);
2039 if(winnt_key) RegCloseKey(winnt_key);
2043 static void delete_external_font_keys(void)
2045 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2046 DWORD dlen, vlen, datalen, valuelen, i, type;
2050 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2051 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2052 ERR("Can't create Windows font reg key\n");
2056 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2057 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2058 ERR("Can't create Windows font reg key\n");
2062 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2063 ERR("Can't create external font reg key\n");
2067 /* Delete all external fonts added last time */
2069 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2070 &valuelen, &datalen, NULL, NULL);
2071 valuelen++; /* returned value doesn't include room for '\0' */
2072 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2073 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2075 dlen = datalen * sizeof(WCHAR);
2078 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2079 &dlen) == ERROR_SUCCESS) {
2081 RegDeleteValueW(winnt_key, valueW);
2082 RegDeleteValueW(win9x_key, valueW);
2083 /* reset dlen and vlen */
2087 HeapFree(GetProcessHeap(), 0, data);
2088 HeapFree(GetProcessHeap(), 0, valueW);
2090 /* Delete the old external fonts key */
2091 RegCloseKey(external_key);
2092 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2095 if(win9x_key) RegCloseKey(win9x_key);
2096 if(winnt_key) RegCloseKey(winnt_key);
2099 /*************************************************************
2100 * WineEngAddFontResourceEx
2103 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2109 if (ft_handle) /* do it only if we have freetype up and running */
2114 FIXME("Ignoring flags %x\n", flags);
2116 if((unixname = wine_get_unix_file_name(file)))
2118 EnterCriticalSection( &freetype_cs );
2119 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2120 LeaveCriticalSection( &freetype_cs );
2121 HeapFree(GetProcessHeap(), 0, unixname);
2123 if (!ret && !strchrW(file, '\\')) {
2124 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2125 ret = load_font_from_winfonts_dir(file);
2127 /* Try in datadir/fonts (or builddir/fonts),
2128 * needed for Magic the Gathering Online
2130 ret = load_font_from_data_dir(file);
2137 /*************************************************************
2138 * WineEngAddFontMemResourceEx
2141 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2145 if (ft_handle) /* do it only if we have freetype up and running */
2147 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2149 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2150 memcpy(pFontCopy, pbFont, cbFont);
2152 EnterCriticalSection( &freetype_cs );
2153 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2154 LeaveCriticalSection( &freetype_cs );
2158 TRACE("AddFontToList failed\n");
2159 HeapFree(GetProcessHeap(), 0, pFontCopy);
2162 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2163 * For now return something unique but quite random
2165 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2166 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2173 /*************************************************************
2174 * WineEngRemoveFontResourceEx
2177 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2180 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2184 static const struct nls_update_font_list
2186 UINT ansi_cp, oem_cp;
2187 const char *oem, *fixed, *system;
2188 const char *courier, *serif, *small, *sserif;
2189 /* these are for font substitutes */
2190 const char *shelldlg, *tmsrmn;
2191 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2195 const char *from, *to;
2196 } arial_0, courier_new_0, times_new_roman_0;
2197 } nls_update_font_list[] =
2199 /* Latin 1 (United States) */
2200 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2201 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2202 "Tahoma","Times New Roman",
2203 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2206 /* Latin 1 (Multilingual) */
2207 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2208 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2209 "Tahoma","Times New Roman", /* FIXME unverified */
2210 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2213 /* Eastern Europe */
2214 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2215 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,238", "System,238",
2218 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2219 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2220 { "Arial CE,0", "Arial,238" },
2221 { "Courier New CE,0", "Courier New,238" },
2222 { "Times New Roman CE,0", "Times New Roman,238" }
2225 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2226 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 "Fixedsys,204", "System,204",
2229 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2230 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2231 { "Arial Cyr,0", "Arial,204" },
2232 { "Courier New Cyr,0", "Courier New,204" },
2233 { "Times New Roman Cyr,0", "Times New Roman,204" }
2236 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2237 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2238 "Tahoma","Times New Roman", /* FIXME unverified */
2239 "Fixedsys,161", "System,161",
2240 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2241 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2242 { "Arial Greek,0", "Arial,161" },
2243 { "Courier New Greek,0", "Courier New,161" },
2244 { "Times New Roman Greek,0", "Times New Roman,161" }
2247 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2248 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2249 "Tahoma","Times New Roman", /* FIXME unverified */
2250 "Fixedsys,162", "System,162",
2251 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2252 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2253 { "Arial Tur,0", "Arial,162" },
2254 { "Courier New Tur,0", "Courier New,162" },
2255 { "Times New Roman Tur,0", "Times New Roman,162" }
2258 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2259 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2260 "Tahoma","Times New Roman", /* FIXME unverified */
2261 "Fixedsys,177", "System,177",
2262 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2263 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2267 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2268 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2269 "Tahoma","Times New Roman", /* FIXME unverified */
2270 "Fixedsys,178", "System,178",
2271 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2272 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2276 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2277 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2278 "Tahoma","Times New Roman", /* FIXME unverified */
2279 "Fixedsys,186", "System,186",
2280 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2281 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2282 { "Arial Baltic,0", "Arial,186" },
2283 { "Courier New Baltic,0", "Courier New,186" },
2284 { "Times New Roman Baltic,0", "Times New Roman,186" }
2287 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2288 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2289 "Tahoma","Times New Roman", /* FIXME unverified */
2290 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2294 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2295 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2296 "Tahoma","Times New Roman", /* FIXME unverified */
2297 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2301 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2302 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2303 "MS UI Gothic","MS Serif",
2304 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2307 /* Chinese Simplified */
2308 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2309 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2310 "SimSun", "NSimSun",
2311 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2315 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2316 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2318 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2321 /* Chinese Traditional */
2322 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2323 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2324 "PMingLiU", "MingLiU",
2325 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2330 static const WCHAR *font_links_list[] =
2332 Lucida_Sans_Unicode,
2333 Microsoft_Sans_Serif,
2337 static const struct font_links_defaults_list
2339 /* Keyed off substitution for "MS Shell Dlg" */
2340 const WCHAR *shelldlg;
2341 /* Maximum of four substitutes, plus terminating NULL pointer */
2342 const WCHAR *substitutes[5];
2343 } font_links_defaults_list[] =
2345 /* Non East-Asian */
2346 { Tahoma, /* FIXME unverified ordering */
2347 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2349 /* Below lists are courtesy of
2350 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2354 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2356 /* Chinese Simplified */
2358 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2362 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2364 /* Chinese Traditional */
2366 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2370 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2372 return ( ansi_cp == 932 /* CP932 for Japanese */
2373 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2374 || ansi_cp == 949 /* CP949 for Korean */
2375 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2378 static inline HKEY create_fonts_NT_registry_key(void)
2382 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2383 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2387 static inline HKEY create_fonts_9x_registry_key(void)
2391 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2392 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2396 static inline HKEY create_config_fonts_registry_key(void)
2400 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2401 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2405 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2407 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2408 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2409 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2410 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2413 static void set_value_key(HKEY hkey, const char *name, const char *value)
2416 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2418 RegDeleteValueA(hkey, name);
2421 static void update_font_info(void)
2423 char buf[40], cpbuf[40];
2426 UINT i, ansi_cp = 0, oem_cp = 0;
2429 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2432 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2433 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2434 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2435 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2436 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2438 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2439 if (is_dbcs_ansi_cp(ansi_cp))
2440 use_default_fallback = TRUE;
2443 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2445 if (!strcmp( buf, cpbuf )) /* already set correctly */
2450 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2452 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2454 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2457 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2461 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2462 nls_update_font_list[i].oem_cp == oem_cp)
2464 hkey = create_config_fonts_registry_key();
2465 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2466 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2467 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2470 hkey = create_fonts_NT_registry_key();
2471 add_font_list(hkey, &nls_update_font_list[i]);
2474 hkey = create_fonts_9x_registry_key();
2475 add_font_list(hkey, &nls_update_font_list[i]);
2478 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2480 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2481 strlen(nls_update_font_list[i].shelldlg)+1);
2482 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2483 strlen(nls_update_font_list[i].tmsrmn)+1);
2485 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2486 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2487 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2488 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2489 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2490 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2491 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2492 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2494 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2495 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2496 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2504 /* Delete the FontSubstitutes from other locales */
2505 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2507 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2508 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2509 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2515 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2517 /* Clear out system links */
2518 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2521 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2531 WCHAR buff[MAX_PATH];
2535 static const WCHAR comma[] = {',',0};
2537 RegDeleteValueW(hkey, name);
2542 for (i = 0; values[i] != NULL; i++)
2545 if (!strcmpiW(name,value))
2547 psub = get_font_subst(&font_subst_list, value, -1);
2549 value = psub->to.name;
2550 family = find_family_from_name(value);
2554 /* Use first extant filename for this Family */
2555 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2559 file = strrchr(face->file, '/');
2568 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2569 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2570 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2571 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2572 if (sizeof(buff)-(data-buff) < entryLen + 1)
2574 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2575 HeapFree(GetProcessHeap(), 0, fileW);
2578 strcpyW(data, fileW);
2579 strcatW(data, comma);
2580 strcatW(data, value);
2582 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2583 HeapFree(GetProcessHeap(), 0, fileW);
2589 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2591 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2593 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2596 static void update_system_links(void)
2604 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2606 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2608 if (disposition == REG_OPENED_EXISTING_KEY)
2610 TRACE("SystemLink key already exists, doing nothing\n");
2615 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2617 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2622 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2624 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2626 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2627 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2629 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2630 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2633 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2635 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2640 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2642 WARN("failed to create SystemLink key\n");
2646 static BOOL init_freetype(void)
2648 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2651 "Wine cannot find the FreeType font library. To enable Wine to\n"
2652 "use TrueType fonts please install a version of FreeType greater than\n"
2653 "or equal to 2.0.5.\n"
2654 "http://www.freetype.org\n");
2658 #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;}
2660 LOAD_FUNCPTR(FT_Vector_Unit)
2661 LOAD_FUNCPTR(FT_Done_Face)
2662 LOAD_FUNCPTR(FT_Get_Char_Index)
2663 LOAD_FUNCPTR(FT_Get_Module)
2664 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2665 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2666 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2667 LOAD_FUNCPTR(FT_Init_FreeType)
2668 LOAD_FUNCPTR(FT_Load_Glyph)
2669 LOAD_FUNCPTR(FT_Matrix_Multiply)
2670 #ifndef FT_MULFIX_INLINED
2671 LOAD_FUNCPTR(FT_MulFix)
2673 LOAD_FUNCPTR(FT_New_Face)
2674 LOAD_FUNCPTR(FT_New_Memory_Face)
2675 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2676 LOAD_FUNCPTR(FT_Outline_Transform)
2677 LOAD_FUNCPTR(FT_Outline_Translate)
2678 LOAD_FUNCPTR(FT_Select_Charmap)
2679 LOAD_FUNCPTR(FT_Set_Charmap)
2680 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2681 LOAD_FUNCPTR(FT_Vector_Transform)
2682 LOAD_FUNCPTR(FT_Render_Glyph)
2685 /* Don't warn if these ones are missing */
2686 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2687 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2688 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2689 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2690 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2691 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2692 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2694 #ifdef HAVE_FREETYPE_FTWINFNT_H
2695 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2697 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2698 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2699 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2700 <= 2.0.3 has FT_Sqrt64 */
2704 if(pFT_Init_FreeType(&library) != 0) {
2705 ERR("Can't init FreeType library\n");
2706 wine_dlclose(ft_handle, NULL, 0);
2710 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2711 if (pFT_Library_Version)
2712 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2714 if (FT_Version.major<=0)
2720 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2721 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2722 ((FT_Version.minor << 8) & 0x00ff00) |
2723 ((FT_Version.patch ) & 0x0000ff);
2729 "Wine cannot find certain functions that it needs inside the FreeType\n"
2730 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2731 "FreeType to at least version 2.0.5.\n"
2732 "http://www.freetype.org\n");
2733 wine_dlclose(ft_handle, NULL, 0);
2738 /*************************************************************
2741 * Initialize FreeType library and create a list of available faces
2743 BOOL WineEngInit(void)
2745 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2746 static const WCHAR pathW[] = {'P','a','t','h',0};
2748 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2749 WCHAR windowsdir[MAX_PATH];
2752 const char *data_dir;
2756 /* update locale dependent font info in registry */
2759 if(!init_freetype()) return FALSE;
2761 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2762 ERR("Failed to create font mutex\n");
2765 WaitForSingleObject(font_mutex, INFINITE);
2767 delete_external_font_keys();
2769 /* load the system bitmap fonts */
2770 load_system_fonts();
2772 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2773 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2774 strcatW(windowsdir, fontsW);
2775 if((unixname = wine_get_unix_file_name(windowsdir)))
2777 ReadFontDir(unixname, FALSE);
2778 HeapFree(GetProcessHeap(), 0, unixname);
2781 /* load the system truetype fonts */
2782 data_dir = wine_get_data_dir();
2783 if (!data_dir) data_dir = wine_get_build_dir();
2784 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2785 strcpy(unixname, data_dir);
2786 strcat(unixname, "/fonts/");
2787 ReadFontDir(unixname, TRUE);
2788 HeapFree(GetProcessHeap(), 0, unixname);
2791 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2792 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2793 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2795 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2796 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2797 &hkey) == ERROR_SUCCESS) {
2798 LPWSTR data, valueW;
2799 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2800 &valuelen, &datalen, NULL, NULL);
2802 valuelen++; /* returned value doesn't include room for '\0' */
2803 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2804 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2807 dlen = datalen * sizeof(WCHAR);
2809 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2810 &dlen) == ERROR_SUCCESS) {
2811 if(data[0] && (data[1] == ':'))
2813 if((unixname = wine_get_unix_file_name(data)))
2815 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2816 HeapFree(GetProcessHeap(), 0, unixname);
2819 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2821 WCHAR pathW[MAX_PATH];
2822 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2825 sprintfW(pathW, fmtW, windowsdir, data);
2826 if((unixname = wine_get_unix_file_name(pathW)))
2828 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2829 HeapFree(GetProcessHeap(), 0, unixname);
2832 load_font_from_data_dir(data);
2834 /* reset dlen and vlen */
2839 HeapFree(GetProcessHeap(), 0, data);
2840 HeapFree(GetProcessHeap(), 0, valueW);
2844 load_fontconfig_fonts();
2846 /* then look in any directories that we've specified in the config file */
2847 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2848 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2854 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2856 len += sizeof(WCHAR);
2857 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2858 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2860 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2861 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2862 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2863 TRACE( "got font path %s\n", debugstr_a(valueA) );
2867 LPSTR next = strchr( ptr, ':' );
2868 if (next) *next++ = 0;
2869 ReadFontDir( ptr, TRUE );
2872 HeapFree( GetProcessHeap(), 0, valueA );
2874 HeapFree( GetProcessHeap(), 0, valueW );
2883 update_reg_entries();
2885 update_system_links();
2886 init_system_links();
2888 ReleaseMutex(font_mutex);
2893 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2896 TT_HoriHeader *pHori;
2900 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2901 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2903 if(height == 0) height = 16;
2905 /* Calc. height of EM square:
2907 * For +ve lfHeight we have
2908 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2909 * Re-arranging gives:
2910 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2912 * For -ve lfHeight we have
2914 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2915 * with il = winAscent + winDescent - units_per_em]
2920 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2921 ppem = MulDiv(ft_face->units_per_EM, height,
2922 pHori->Ascender - pHori->Descender);
2924 ppem = MulDiv(ft_face->units_per_EM, height,
2925 pOS2->usWinAscent + pOS2->usWinDescent);
2933 static struct font_mapping *map_font_file( const char *name )
2935 struct font_mapping *mapping;
2939 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2940 if (fstat( fd, &st ) == -1) goto error;
2942 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2944 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2946 mapping->refcount++;
2951 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2954 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2957 if (mapping->data == MAP_FAILED)
2959 HeapFree( GetProcessHeap(), 0, mapping );
2962 mapping->refcount = 1;
2963 mapping->dev = st.st_dev;
2964 mapping->ino = st.st_ino;
2965 mapping->size = st.st_size;
2966 list_add_tail( &mappings_list, &mapping->entry );
2974 static void unmap_font_file( struct font_mapping *mapping )
2976 if (!--mapping->refcount)
2978 list_remove( &mapping->entry );
2979 munmap( mapping->data, mapping->size );
2980 HeapFree( GetProcessHeap(), 0, mapping );
2984 static LONG load_VDMX(GdiFont*, LONG);
2986 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2993 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2997 if (!(font->mapping = map_font_file( face->file )))
2999 WARN("failed to map %s\n", debugstr_a(face->file));
3002 data_ptr = font->mapping->data;
3003 data_size = font->mapping->size;
3007 data_ptr = face->font_data_ptr;
3008 data_size = face->font_data_size;
3011 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3013 ERR("FT_New_Face rets %d\n", err);
3017 /* set it here, as load_VDMX needs it */
3018 font->ft_face = ft_face;
3020 if(FT_IS_SCALABLE(ft_face)) {
3021 /* load the VDMX table if we have one */
3022 font->ppem = load_VDMX(font, height);
3024 font->ppem = calc_ppem_for_height(ft_face, height);
3025 TRACE("height %d => ppem %d\n", height, font->ppem);
3027 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3028 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3030 font->ppem = height;
3031 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3032 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3038 static int get_nearest_charset(Face *face, int *cp)
3040 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3041 a single face with the requested charset. The idea is to check if
3042 the selected font supports the current ANSI codepage, if it does
3043 return the corresponding charset, else return the first charset */
3046 int acp = GetACP(), i;
3050 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3051 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3052 return csi.ciCharset;
3054 for(i = 0; i < 32; i++) {
3056 if(face->fs.fsCsb[0] & fs0) {
3057 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3059 return csi.ciCharset;
3062 FIXME("TCI failing on %x\n", fs0);
3066 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3067 face->fs.fsCsb[0], face->file);
3069 return DEFAULT_CHARSET;
3072 static GdiFont *alloc_font(void)
3074 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3076 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3077 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3079 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3080 ret->total_kern_pairs = (DWORD)-1;
3081 ret->kern_pairs = NULL;
3082 list_init(&ret->hfontlist);
3083 list_init(&ret->child_fonts);
3087 static void free_font(GdiFont *font)
3089 struct list *cursor, *cursor2;
3092 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3094 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3095 list_remove(cursor);
3097 free_font(child->font);
3098 HeapFree(GetProcessHeap(), 0, child);
3101 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3103 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3104 DeleteObject(hfontlist->hfont);
3105 list_remove(&hfontlist->entry);
3106 HeapFree(GetProcessHeap(), 0, hfontlist);
3109 if (font->ft_face) pFT_Done_Face(font->ft_face);
3110 if (font->mapping) unmap_font_file( font->mapping );
3111 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3112 HeapFree(GetProcessHeap(), 0, font->potm);
3113 HeapFree(GetProcessHeap(), 0, font->name);
3114 for (i = 0; i < font->gmsize; i++)
3115 HeapFree(GetProcessHeap(),0,font->gm[i]);
3116 HeapFree(GetProcessHeap(), 0, font->gm);
3117 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3118 HeapFree(GetProcessHeap(), 0, font);
3122 /*************************************************************
3125 * load the vdmx entry for the specified height
3128 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3129 ( ( (FT_ULong)_x4 << 24 ) | \
3130 ( (FT_ULong)_x3 << 16 ) | \
3131 ( (FT_ULong)_x2 << 8 ) | \
3134 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3149 static LONG load_VDMX(GdiFont *font, LONG height)
3153 BYTE devXRatio, devYRatio;
3154 USHORT numRecs, numRatios;
3155 DWORD result, offset = -1;
3159 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3161 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3164 /* FIXME: need the real device aspect ratio */
3168 numRecs = GET_BE_WORD(hdr[1]);
3169 numRatios = GET_BE_WORD(hdr[2]);
3171 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3172 for(i = 0; i < numRatios; i++) {
3175 offset = (3 * 2) + (i * sizeof(Ratios));
3176 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3179 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3181 if((ratio.xRatio == 0 &&
3182 ratio.yStartRatio == 0 &&
3183 ratio.yEndRatio == 0) ||
3184 (devXRatio == ratio.xRatio &&
3185 devYRatio >= ratio.yStartRatio &&
3186 devYRatio <= ratio.yEndRatio))
3188 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3189 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3190 offset = GET_BE_WORD(tmp);
3196 FIXME("No suitable ratio found\n");
3200 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3202 BYTE startsz, endsz;
3205 recs = GET_BE_WORD(group.recs);
3206 startsz = group.startsz;
3207 endsz = group.endsz;
3209 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3211 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3212 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3213 if(result == GDI_ERROR) {
3214 FIXME("Failed to retrieve vTable\n");
3219 for(i = 0; i < recs; i++) {
3220 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3221 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3222 ppem = GET_BE_WORD(vTable[i * 3]);
3224 if(yMax + -yMin == height) {
3227 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3230 if(yMax + -yMin > height) {
3233 goto end; /* failed */
3235 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3236 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3237 ppem = GET_BE_WORD(vTable[i * 3]);
3238 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3244 TRACE("ppem not found for height %d\n", height);
3248 HeapFree(GetProcessHeap(), 0, vTable);
3254 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3256 if(font->font_desc.hash != fd->hash) return TRUE;
3257 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3258 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3259 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3260 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3263 static void calc_hash(FONT_DESC *pfd)
3265 DWORD hash = 0, *ptr, two_chars;
3269 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3271 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3273 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3275 pwc = (WCHAR *)&two_chars;
3277 *pwc = toupperW(*pwc);
3279 *pwc = toupperW(*pwc);
3283 hash ^= !pfd->can_use_bitmap;
3288 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3293 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3297 fd.can_use_bitmap = can_use_bitmap;
3300 /* try the child list */
3301 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3302 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3303 if(!fontcmp(ret, &fd)) {
3304 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3305 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3306 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3307 if(hflist->hfont == hfont)
3313 /* try the in-use list */
3314 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3315 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3316 if(!fontcmp(ret, &fd)) {
3317 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3318 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3319 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3320 if(hflist->hfont == hfont)
3323 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3324 hflist->hfont = hfont;
3325 list_add_head(&ret->hfontlist, &hflist->entry);
3330 /* then the unused list */
3331 font_elem_ptr = list_head(&unused_gdi_font_list);
3332 while(font_elem_ptr) {
3333 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3334 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3335 if(!fontcmp(ret, &fd)) {
3336 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3337 assert(list_empty(&ret->hfontlist));
3338 TRACE("Found %p in unused list\n", ret);
3339 list_remove(&ret->entry);
3340 list_add_head(&gdi_font_list, &ret->entry);
3341 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3342 hflist->hfont = hfont;
3343 list_add_head(&ret->hfontlist, &hflist->entry);
3350 static void add_to_cache(GdiFont *font)
3352 static DWORD cache_num = 1;
3354 font->cache_num = cache_num++;
3355 list_add_head(&gdi_font_list, &font->entry);
3358 /*************************************************************
3359 * create_child_font_list
3361 static BOOL create_child_font_list(GdiFont *font)
3364 SYSTEM_LINKS *font_link;
3365 CHILD_FONT *font_link_entry, *new_child;
3369 psub = get_font_subst(&font_subst_list, font->name, -1);
3370 font_name = psub ? psub->to.name : font->name;
3371 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3373 if(!strcmpiW(font_link->font_name, font_name))
3375 TRACE("found entry in system list\n");
3376 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3378 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3379 new_child->face = font_link_entry->face;
3380 new_child->font = NULL;
3381 list_add_tail(&font->child_fonts, &new_child->entry);
3382 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3389 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3390 * Sans Serif. This is how asian windows get default fallbacks for fonts
3392 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3393 font->charset != OEM_CHARSET &&
3394 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3395 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3397 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3399 TRACE("found entry in default fallback list\n");
3400 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3402 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3403 new_child->face = font_link_entry->face;
3404 new_child->font = NULL;
3405 list_add_tail(&font->child_fonts, &new_child->entry);
3406 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3416 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3418 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3420 if (pFT_Set_Charmap)
3423 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3425 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3427 for (i = 0; i < ft_face->num_charmaps; i++)
3429 if (ft_face->charmaps[i]->encoding == encoding)
3431 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3432 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3434 switch (ft_face->charmaps[i]->platform_id)
3437 cmap_def = ft_face->charmaps[i];
3439 case 0: /* Apple Unicode */
3440 cmap0 = ft_face->charmaps[i];
3442 case 1: /* Macintosh */
3443 cmap1 = ft_face->charmaps[i];
3446 cmap2 = ft_face->charmaps[i];
3448 case 3: /* Microsoft */
3449 cmap3 = ft_face->charmaps[i];
3454 if (cmap3) /* prefer Microsoft cmap table */
3455 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3457 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3459 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3461 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3463 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3465 return ft_err == FT_Err_Ok;
3468 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3471 /*************************************************************
3472 * WineEngCreateFontInstance
3475 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3478 Face *face, *best, *best_bitmap;
3479 Family *family, *last_resort_family;
3480 struct list *family_elem_ptr, *face_elem_ptr;
3481 INT height, width = 0;
3482 unsigned int score = 0, new_score;
3483 signed int diff = 0, newdiff;
3484 BOOL bd, it, can_use_bitmap;
3489 FontSubst *psub = NULL;
3491 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3492 lf.lfWidth = abs(lf.lfWidth);
3494 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3496 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3497 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3498 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3501 if(dc->GraphicsMode == GM_ADVANCED)
3502 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3505 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3506 font scaling abilities. */
3507 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3508 dcmat.eM21 = dcmat.eM12 = 0;
3511 /* Try to avoid not necessary glyph transformations */
3512 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3514 lf.lfHeight *= fabs(dcmat.eM11);
3515 lf.lfWidth *= fabs(dcmat.eM11);
3516 dcmat.eM11 = dcmat.eM22 = 1.0;
3519 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3520 dcmat.eM21, dcmat.eM22);
3523 EnterCriticalSection( &freetype_cs );
3525 /* check the cache first */
3526 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3527 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3528 LeaveCriticalSection( &freetype_cs );
3532 TRACE("not in cache\n");
3533 if(list_empty(&font_list)) /* No fonts installed */
3535 TRACE("No fonts installed\n");
3536 LeaveCriticalSection( &freetype_cs );
3542 ret->font_desc.matrix = dcmat;
3543 ret->font_desc.lf = lf;
3544 ret->font_desc.can_use_bitmap = can_use_bitmap;
3545 calc_hash(&ret->font_desc);
3546 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3547 hflist->hfont = hfont;
3548 list_add_head(&ret->hfontlist, &hflist->entry);
3550 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3551 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3552 original value lfCharSet. Note this is a special case for
3553 Symbol and doesn't happen at least for "Wingdings*" */
3555 if(!strcmpiW(lf.lfFaceName, SymbolW))
3556 lf.lfCharSet = SYMBOL_CHARSET;
3558 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3559 switch(lf.lfCharSet) {
3560 case DEFAULT_CHARSET:
3561 csi.fs.fsCsb[0] = 0;
3564 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3565 csi.fs.fsCsb[0] = 0;
3571 if(lf.lfFaceName[0] != '\0') {
3572 SYSTEM_LINKS *font_link;
3573 CHILD_FONT *font_link_entry;
3574 LPWSTR FaceName = lf.lfFaceName;
3577 * Check for a leading '@' this signals that the font is being
3578 * requested in tategaki mode (vertical writing substitution) but
3579 * does not affect the fontface that is to be selected.
3581 if (lf.lfFaceName[0]=='@')
3582 FaceName = &lf.lfFaceName[1];
3584 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3587 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3588 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3589 if (psub->to.charset != -1)
3590 lf.lfCharSet = psub->to.charset;
3593 /* We want a match on name and charset or just name if
3594 charset was DEFAULT_CHARSET. If the latter then
3595 we fixup the returned charset later in get_nearest_charset
3596 where we'll either use the charset of the current ansi codepage
3597 or if that's unavailable the first charset that the font supports.
3599 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3600 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3601 if (!strcmpiW(family->FamilyName, FaceName) ||
3602 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3604 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3605 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3606 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3607 if(face->scalable || can_use_bitmap)
3614 * Try check the SystemLink list first for a replacement font.
3615 * We may find good replacements there.
3617 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3619 if(!strcmpiW(font_link->font_name, FaceName) ||
3620 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3622 TRACE("found entry in system list\n");
3623 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3625 face = font_link_entry->face;
3626 family = face->family;
3627 if(csi.fs.fsCsb[0] &
3628 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3630 if(face->scalable || can_use_bitmap)
3638 psub = NULL; /* substitution is no more relevant */
3640 /* If requested charset was DEFAULT_CHARSET then try using charset
3641 corresponding to the current ansi codepage */
3642 if (!csi.fs.fsCsb[0])
3645 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3646 FIXME("TCI failed on codepage %d\n", acp);
3647 csi.fs.fsCsb[0] = 0;
3649 lf.lfCharSet = csi.ciCharset;
3652 /* Face families are in the top 4 bits of lfPitchAndFamily,
3653 so mask with 0xF0 before testing */
3655 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3656 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3657 strcpyW(lf.lfFaceName, defFixed);
3658 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3659 strcpyW(lf.lfFaceName, defSerif);
3660 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3661 strcpyW(lf.lfFaceName, defSans);
3663 strcpyW(lf.lfFaceName, defSans);
3664 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3665 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3666 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3667 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3668 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3669 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3670 if(face->scalable || can_use_bitmap)
3676 last_resort_family = NULL;
3677 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3678 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3679 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3680 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3681 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3684 if(can_use_bitmap && !last_resort_family)
3685 last_resort_family = family;
3690 if(last_resort_family) {
3691 family = last_resort_family;
3692 csi.fs.fsCsb[0] = 0;
3696 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3697 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3698 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3699 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3700 if(face->scalable) {
3701 csi.fs.fsCsb[0] = 0;
3702 WARN("just using first face for now\n");
3705 if(can_use_bitmap && !last_resort_family)
3706 last_resort_family = family;
3709 if(!last_resort_family) {
3710 FIXME("can't find a single appropriate font - bailing\n");
3712 LeaveCriticalSection( &freetype_cs );
3716 WARN("could only find a bitmap font - this will probably look awful!\n");
3717 family = last_resort_family;
3718 csi.fs.fsCsb[0] = 0;
3721 it = lf.lfItalic ? 1 : 0;
3722 bd = lf.lfWeight > 550 ? 1 : 0;
3724 height = lf.lfHeight;
3726 face = best = best_bitmap = NULL;
3727 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3729 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3733 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3734 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3735 new_score = (italic ^ it) + (bold ^ bd);
3736 if(!best || new_score <= score)
3738 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3739 italic, bold, it, bd);
3742 if(best->scalable && score == 0) break;
3746 newdiff = height - (signed int)(best->size.height);
3748 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3749 if(!best_bitmap || new_score < score ||
3750 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3752 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3755 if(score == 0 && diff == 0) break;
3762 face = best->scalable ? best : best_bitmap;
3763 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3764 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3768 if(csi.fs.fsCsb[0]) {
3769 ret->charset = lf.lfCharSet;
3770 ret->codepage = csi.ciACP;
3773 ret->charset = get_nearest_charset(face, &ret->codepage);
3775 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3776 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3778 ret->aveWidth = height ? lf.lfWidth : 0;
3780 if(!face->scalable) {
3781 /* Windows uses integer scaling factors for bitmap fonts */
3782 INT scale, scaled_height;
3783 GdiFont *cachedfont;
3785 /* FIXME: rotation of bitmap fonts is ignored */
3786 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3788 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3789 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3790 dcmat.eM11 = dcmat.eM22 = 1.0;
3791 /* As we changed the matrix, we need to search the cache for the font again,
3792 * otherwise we might explode the cache. */
3793 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3794 TRACE("Found cached font after non-scalable matrix rescale!\n");
3796 LeaveCriticalSection( &freetype_cs );
3799 calc_hash(&ret->font_desc);
3801 if (height != 0) height = diff;
3802 height += face->size.height;
3804 scale = (height + face->size.height - 1) / face->size.height;
3805 scaled_height = scale * face->size.height;
3806 /* Only jump to the next height if the difference <= 25% original height */
3807 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3808 /* The jump between unscaled and doubled is delayed by 1 */
3809 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3810 ret->scale_y = scale;
3812 width = face->size.x_ppem >> 6;
3813 height = face->size.y_ppem >> 6;
3817 TRACE("font scale y: %f\n", ret->scale_y);
3819 ret->ft_face = OpenFontFace(ret, face, width, height);
3824 LeaveCriticalSection( &freetype_cs );
3828 ret->ntmFlags = face->ntmFlags;
3830 if (ret->charset == SYMBOL_CHARSET &&
3831 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3834 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3838 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3841 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3842 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3843 ret->underline = lf.lfUnderline ? 0xff : 0;
3844 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3845 create_child_font_list(ret);
3847 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3849 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3850 if (length != GDI_ERROR)
3852 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3853 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3854 TRACE("Loaded GSUB table of %i bytes\n",length);
3858 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3861 LeaveCriticalSection( &freetype_cs );
3865 static void dump_gdi_font_list(void)
3868 struct list *elem_ptr;
3870 TRACE("---------- gdiFont Cache ----------\n");
3871 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3872 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3873 TRACE("gdiFont=%p %s %d\n",
3874 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3877 TRACE("---------- Unused gdiFont Cache ----------\n");
3878 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3879 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3880 TRACE("gdiFont=%p %s %d\n",
3881 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3884 TRACE("---------- Child gdiFont Cache ----------\n");
3885 LIST_FOR_EACH(elem_ptr, &child_font_list) {
3886 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3887 TRACE("gdiFont=%p %s %d\n",
3888 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3892 /*************************************************************
3893 * WineEngDestroyFontInstance
3895 * free the gdiFont associated with this handle
3898 BOOL WineEngDestroyFontInstance(HFONT handle)
3903 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3907 EnterCriticalSection( &freetype_cs );
3909 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3911 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3912 while(hfontlist_elem_ptr) {
3913 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3914 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3915 if(hflist->hfont == handle) {
3916 TRACE("removing child font %p from child list\n", gdiFont);
3917 list_remove(&gdiFont->entry);
3918 LeaveCriticalSection( &freetype_cs );
3924 TRACE("destroying hfont=%p\n", handle);
3926 dump_gdi_font_list();
3928 font_elem_ptr = list_head(&gdi_font_list);
3929 while(font_elem_ptr) {
3930 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3931 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3933 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3934 while(hfontlist_elem_ptr) {
3935 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3936 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3937 if(hflist->hfont == handle) {
3938 list_remove(&hflist->entry);
3939 HeapFree(GetProcessHeap(), 0, hflist);
3943 if(list_empty(&gdiFont->hfontlist)) {
3944 TRACE("Moving to Unused list\n");
3945 list_remove(&gdiFont->entry);
3946 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3951 font_elem_ptr = list_head(&unused_gdi_font_list);
3952 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3953 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3954 while(font_elem_ptr) {
3955 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3956 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3957 TRACE("freeing %p\n", gdiFont);
3958 list_remove(&gdiFont->entry);
3961 LeaveCriticalSection( &freetype_cs );
3965 /***************************************************
3966 * create_enum_charset_list
3968 * This function creates charset enumeration list because in DEFAULT_CHARSET
3969 * case, the ANSI codepage's charset takes precedence over other charsets.
3970 * This function works as a filter other than DEFAULT_CHARSET case.
3972 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
3977 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
3978 csi.fs.fsCsb[0] != 0) {
3979 list->element[n].mask = csi.fs.fsCsb[0];
3980 list->element[n].charset = csi.ciCharset;
3981 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
3984 else { /* charset is DEFAULT_CHARSET or invalid. */
3987 /* Set the current codepage's charset as the first element. */
3989 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
3990 csi.fs.fsCsb[0] != 0) {
3991 list->element[n].mask = csi.fs.fsCsb[0];
3992 list->element[n].charset = csi.ciCharset;
3993 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
3997 /* Fill out left elements. */
3998 for (i = 0; i < 32; i++) {
4000 fs.fsCsb[0] = 1L << i;
4002 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4003 continue; /* skip, already added. */
4004 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4005 continue; /* skip, this is an invalid fsCsb bit. */
4007 list->element[n].mask = fs.fsCsb[0];
4008 list->element[n].charset = csi.ciCharset;
4009 list->element[n].name = ElfScriptsW[i];
4018 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4019 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4024 if (face->cached_enum_data)
4027 *pelf = face->cached_enum_data->elf;
4028 *pntm = face->cached_enum_data->ntm;
4029 *ptype = face->cached_enum_data->type;
4033 font = alloc_font();
4035 if(face->scalable) {
4036 height = -2048; /* 2048 is the most common em size */
4039 height = face->size.y_ppem >> 6;
4040 width = face->size.x_ppem >> 6;
4042 font->scale_y = 1.0;
4044 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4050 font->name = strdupW(face->family->FamilyName);
4051 font->ntmFlags = face->ntmFlags;
4053 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4055 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4057 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4059 lstrcpynW(pelf->elfLogFont.lfFaceName,
4060 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4062 lstrcpynW(pelf->elfFullName,
4063 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4065 lstrcpynW(pelf->elfStyle,
4066 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4071 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4073 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4075 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4076 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4077 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4080 pntm->ntmTm.ntmFlags = face->ntmFlags;
4081 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4082 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4083 pntm->ntmFontSig = face->fs;
4085 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4087 pelf->elfLogFont.lfEscapement = 0;
4088 pelf->elfLogFont.lfOrientation = 0;
4089 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4090 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4091 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4092 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4093 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4094 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4095 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4096 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4097 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4098 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4099 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4102 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4103 *ptype |= TRUETYPE_FONTTYPE;
4104 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4105 *ptype |= DEVICE_FONTTYPE;
4106 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4107 *ptype |= RASTER_FONTTYPE;
4109 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4110 if (face->cached_enum_data)
4112 face->cached_enum_data->elf = *pelf;
4113 face->cached_enum_data->ntm = *pntm;
4114 face->cached_enum_data->type = *ptype;
4120 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4122 struct list *face_elem_ptr;
4124 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4126 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4128 static const WCHAR spaceW[] = { ' ',0 };
4129 WCHAR full_family_name[LF_FULLFACESIZE];
4130 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4132 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4134 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4135 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4139 strcpyW(full_family_name, family->FamilyName);
4140 strcatW(full_family_name, spaceW);
4141 strcatW(full_family_name, face->StyleName);
4142 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4148 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4150 static const WCHAR spaceW[] = { ' ',0 };
4151 WCHAR full_family_name[LF_FULLFACESIZE];
4153 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4155 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4157 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4158 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4162 strcpyW(full_family_name, face->family->FamilyName);
4163 strcatW(full_family_name, spaceW);
4164 strcatW(full_family_name, face->StyleName);
4165 return !strcmpiW(lf->lfFaceName, full_family_name);
4168 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4169 FONTENUMPROCW proc, LPARAM lparam)
4172 NEWTEXTMETRICEXW ntm;
4176 GetEnumStructs(face, &elf, &ntm, &type);
4177 for(i = 0; i < list->total; i++) {
4178 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4179 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4180 strcpyW(elf.elfScript, OEM_DOSW);
4181 i = 32; /* break out of loop */
4182 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4185 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4186 if(list->element[i].name)
4187 strcpyW(elf.elfScript, list->element[i].name);
4189 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4191 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4192 debugstr_w(elf.elfLogFont.lfFaceName),
4193 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4194 list->element[i].charset, type, debugstr_w(elf.elfScript),
4195 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4196 ntm.ntmTm.ntmFlags);
4197 /* release section before callback (FIXME) */
4198 LeaveCriticalSection( &freetype_cs );
4199 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4200 EnterCriticalSection( &freetype_cs );
4205 /*************************************************************
4209 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4213 struct list *family_elem_ptr, *face_elem_ptr;
4215 struct enum_charset_list enum_charsets;
4219 lf.lfCharSet = DEFAULT_CHARSET;
4220 lf.lfPitchAndFamily = 0;
4221 lf.lfFaceName[0] = 0;
4225 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4227 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4230 EnterCriticalSection( &freetype_cs );
4231 if(plf->lfFaceName[0]) {
4233 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4236 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4237 debugstr_w(psub->to.name));
4239 strcpyW(lf.lfFaceName, psub->to.name);
4243 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4244 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4245 if(family_matches(family, plf)) {
4246 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4247 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4248 if (!face_matches(face, plf)) continue;
4249 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4254 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4255 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4256 face_elem_ptr = list_head(&family->faces);
4257 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4258 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4261 LeaveCriticalSection( &freetype_cs );
4265 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4267 pt->x.value = vec->x >> 6;
4268 pt->x.fract = (vec->x & 0x3f) << 10;
4269 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4270 pt->y.value = vec->y >> 6;
4271 pt->y.fract = (vec->y & 0x3f) << 10;
4272 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4276 /***************************************************
4277 * According to the MSDN documentation on WideCharToMultiByte,
4278 * certain codepages cannot set the default_used parameter.
4279 * This returns TRUE if the codepage can set that parameter, false else
4280 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4282 static BOOL codepage_sets_default_used(UINT codepage)
4296 * GSUB Table handling functions
4299 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4301 const GSUB_CoverageFormat1* cf1;
4305 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4307 int count = GET_BE_WORD(cf1->GlyphCount);
4309 TRACE("Coverage Format 1, %i glyphs\n",count);
4310 for (i = 0; i < count; i++)
4311 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4315 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4317 const GSUB_CoverageFormat2* cf2;
4320 cf2 = (const GSUB_CoverageFormat2*)cf1;
4322 count = GET_BE_WORD(cf2->RangeCount);
4323 TRACE("Coverage Format 2, %i ranges\n",count);
4324 for (i = 0; i < count; i++)
4326 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4328 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4329 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4331 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4332 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4338 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4343 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4345 const GSUB_ScriptList *script;
4346 const GSUB_Script *deflt = NULL;
4348 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4350 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4351 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4353 const GSUB_Script *scr;
4356 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4357 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4359 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4361 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4367 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4371 const GSUB_LangSys *Lang;
4373 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4375 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4377 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4378 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4380 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4383 offset = GET_BE_WORD(script->DefaultLangSys);
4386 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4392 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4395 const GSUB_FeatureList *feature;
4396 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4398 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4399 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4401 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4402 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4404 const GSUB_Feature *feat;
4405 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4412 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4416 const GSUB_LookupList *lookup;
4417 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4419 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4420 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4422 const GSUB_LookupTable *look;
4423 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4424 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4425 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4426 if (GET_BE_WORD(look->LookupType) != 1)
4427 FIXME("We only handle SubType 1\n");
4432 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4434 const GSUB_SingleSubstFormat1 *ssf1;
4435 offset = GET_BE_WORD(look->SubTable[j]);
4436 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4437 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4439 int offset = GET_BE_WORD(ssf1->Coverage);
4440 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4441 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4443 TRACE(" Glyph 0x%x ->",glyph);
4444 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4445 TRACE(" 0x%x\n",glyph);
4450 const GSUB_SingleSubstFormat2 *ssf2;
4454 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4455 offset = GET_BE_WORD(ssf1->Coverage);
4456 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4457 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4458 TRACE(" Coverage index %i\n",index);
4461 TRACE(" Glyph is 0x%x ->",glyph);
4462 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4463 TRACE("0x%x\n",glyph);
4472 static const char* get_opentype_script(const GdiFont *font)
4475 * I am not sure if this is the correct way to generate our script tag
4478 switch (font->charset)
4480 case ANSI_CHARSET: return "latn";
4481 case BALTIC_CHARSET: return "latn"; /* ?? */
4482 case CHINESEBIG5_CHARSET: return "hani";
4483 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4484 case GB2312_CHARSET: return "hani";
4485 case GREEK_CHARSET: return "grek";
4486 case HANGUL_CHARSET: return "hang";
4487 case RUSSIAN_CHARSET: return "cyrl";
4488 case SHIFTJIS_CHARSET: return "kana";
4489 case TURKISH_CHARSET: return "latn"; /* ?? */
4490 case VIETNAMESE_CHARSET: return "latn";
4491 case JOHAB_CHARSET: return "latn"; /* ?? */
4492 case ARABIC_CHARSET: return "arab";
4493 case HEBREW_CHARSET: return "hebr";
4494 case THAI_CHARSET: return "thai";
4495 default: return "latn";
4499 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4501 const GSUB_Header *header;
4502 const GSUB_Script *script;
4503 const GSUB_LangSys *language;
4504 const GSUB_Feature *feature;
4506 if (!font->GSUB_Table)
4509 header = font->GSUB_Table;
4511 script = GSUB_get_script_table(header, get_opentype_script(font));
4514 TRACE("Script not found\n");
4517 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4520 TRACE("Language not found\n");
4523 feature = GSUB_get_feature(header, language, "vrt2");
4525 feature = GSUB_get_feature(header, language, "vert");
4528 TRACE("vrt2/vert feature not found\n");
4531 return GSUB_apply_feature(header, feature, glyph);
4534 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4538 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4539 WCHAR wc = (WCHAR)glyph;
4541 BOOL *default_used_pointer;
4544 default_used_pointer = NULL;
4545 default_used = FALSE;
4546 if (codepage_sets_default_used(font->codepage))
4547 default_used_pointer = &default_used;
4548 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4551 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4552 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4553 return get_GSUB_vert_glyph(font,ret);
4556 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4558 if (glyph < 0x100) glyph += 0xf000;
4559 /* there is a number of old pre-Unicode "broken" TTFs, which
4560 do have symbols at U+00XX instead of U+f0XX */
4561 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4562 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4564 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4566 return get_GSUB_vert_glyph(font,glyphId);
4569 /*************************************************************
4570 * WineEngGetGlyphIndices
4573 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4574 LPWORD pgi, DWORD flags)
4577 int default_char = -1;
4579 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4581 for(i = 0; i < count; i++)
4583 pgi[i] = get_glyph_index(font, lpstr[i]);
4586 if (default_char == -1)
4588 if (FT_IS_SFNT(font->ft_face))
4590 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4591 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4596 WineEngGetTextMetrics(font, &textm);
4597 default_char = textm.tmDefaultChar;
4600 pgi[i] = default_char;
4606 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4608 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4609 return !memcmp(matrix, &identity, sizeof(FMAT2));
4612 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4614 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4615 return !memcmp(matrix, &identity, sizeof(MAT2));
4618 /*************************************************************
4619 * WineEngGetGlyphOutline
4621 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4622 * except that the first parameter is the HWINEENGFONT of the font in
4623 * question rather than an HDC.
4626 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4627 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4630 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4631 FT_Face ft_face = incoming_font->ft_face;
4632 GdiFont *font = incoming_font;
4633 FT_UInt glyph_index;
4634 DWORD width, height, pitch, needed = 0;
4635 FT_Bitmap ft_bitmap;
4637 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4639 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4640 double widthRatio = 1.0;
4641 FT_Matrix transMat = identityMat;
4642 FT_Matrix transMatUnrotated;
4643 BOOL needsTransform = FALSE;
4644 BOOL tategaki = (font->GSUB_Table != NULL);
4645 UINT original_index;
4647 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4648 buflen, buf, lpmat);
4650 TRACE("font transform %f %f %f %f\n",
4651 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4652 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4655 EnterCriticalSection( &freetype_cs );
4657 if(format & GGO_GLYPH_INDEX) {
4658 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4659 original_index = glyph;
4660 format &= ~GGO_GLYPH_INDEX;
4662 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4663 ft_face = font->ft_face;
4664 original_index = glyph_index;
4667 if(format & GGO_UNHINTED) {
4668 load_flags |= FT_LOAD_NO_HINTING;
4669 format &= ~GGO_UNHINTED;
4672 /* tategaki never appears to happen to lower glyph index */
4673 if (glyph_index < TATEGAKI_LOWER_BOUND )
4676 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4677 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4678 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4679 font->gmsize * sizeof(GM*));
4681 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4682 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4684 *lpgm = FONT_GM(font,original_index)->gm;
4685 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4686 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4687 lpgm->gmCellIncX, lpgm->gmCellIncY);
4688 LeaveCriticalSection( &freetype_cs );
4689 return 1; /* FIXME */
4693 if (!font->gm[original_index / GM_BLOCK_SIZE])
4694 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4696 /* Scaling factor */
4701 WineEngGetTextMetrics(font, &tm);
4703 widthRatio = (double)font->aveWidth;
4704 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4707 widthRatio = font->scale_y;
4709 /* Scaling transform */
4710 if (widthRatio != 1.0 || font->scale_y != 1.0)
4713 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4716 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4718 pFT_Matrix_Multiply(&scaleMat, &transMat);
4719 needsTransform = TRUE;
4722 /* Slant transform */
4723 if (font->fake_italic) {
4726 slantMat.xx = (1 << 16);
4727 slantMat.xy = ((1 << 16) >> 2);
4729 slantMat.yy = (1 << 16);
4730 pFT_Matrix_Multiply(&slantMat, &transMat);
4731 needsTransform = TRUE;
4734 /* Rotation transform */
4735 transMatUnrotated = transMat;
4736 if(font->orientation && !tategaki) {
4737 FT_Matrix rotationMat;
4739 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4740 pFT_Vector_Unit(&vecAngle, angle);
4741 rotationMat.xx = vecAngle.x;
4742 rotationMat.xy = -vecAngle.y;
4743 rotationMat.yx = -rotationMat.xy;
4744 rotationMat.yy = rotationMat.xx;
4746 pFT_Matrix_Multiply(&rotationMat, &transMat);
4747 needsTransform = TRUE;
4750 /* World transform */
4751 if (!is_identity_FMAT2(&font->font_desc.matrix))
4754 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4755 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4756 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4757 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4758 pFT_Matrix_Multiply(&worldMat, &transMat);
4759 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4760 needsTransform = TRUE;
4763 /* Extra transformation specified by caller */
4764 if (!is_identity_MAT2(lpmat))
4767 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4768 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4769 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4770 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4771 pFT_Matrix_Multiply(&extraMat, &transMat);
4772 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4773 needsTransform = TRUE;
4776 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4777 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4778 format == GGO_GRAY8_BITMAP))
4780 load_flags |= FT_LOAD_NO_BITMAP;
4783 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4786 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4787 LeaveCriticalSection( &freetype_cs );
4791 if(!needsTransform) {
4792 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4793 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4794 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4796 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4797 bottom = (ft_face->glyph->metrics.horiBearingY -
4798 ft_face->glyph->metrics.height) & -64;
4799 lpgm->gmCellIncX = adv;
4800 lpgm->gmCellIncY = 0;
4807 for(xc = 0; xc < 2; xc++) {
4808 for(yc = 0; yc < 2; yc++) {
4809 vec.x = (ft_face->glyph->metrics.horiBearingX +
4810 xc * ft_face->glyph->metrics.width);
4811 vec.y = ft_face->glyph->metrics.horiBearingY -
4812 yc * ft_face->glyph->metrics.height;
4813 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4814 pFT_Vector_Transform(&vec, &transMat);
4815 if(xc == 0 && yc == 0) {
4816 left = right = vec.x;
4817 top = bottom = vec.y;
4819 if(vec.x < left) left = vec.x;
4820 else if(vec.x > right) right = vec.x;
4821 if(vec.y < bottom) bottom = vec.y;
4822 else if(vec.y > top) top = vec.y;
4827 right = (right + 63) & -64;
4828 bottom = bottom & -64;
4829 top = (top + 63) & -64;
4831 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4832 vec.x = ft_face->glyph->metrics.horiAdvance;
4834 pFT_Vector_Transform(&vec, &transMat);
4835 lpgm->gmCellIncX = (vec.x+63) >> 6;
4836 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4838 vec.x = ft_face->glyph->metrics.horiAdvance;
4840 pFT_Vector_Transform(&vec, &transMatUnrotated);
4841 adv = (vec.x+63) >> 6;
4845 bbx = (right - left) >> 6;
4846 lpgm->gmBlackBoxX = (right - left) >> 6;
4847 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4848 lpgm->gmptGlyphOrigin.x = left >> 6;
4849 lpgm->gmptGlyphOrigin.y = top >> 6;
4851 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4852 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4853 lpgm->gmCellIncX, lpgm->gmCellIncY);
4855 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4856 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4858 FONT_GM(font,original_index)->gm = *lpgm;
4859 FONT_GM(font,original_index)->adv = adv;
4860 FONT_GM(font,original_index)->lsb = lsb;
4861 FONT_GM(font,original_index)->bbx = bbx;
4862 FONT_GM(font,original_index)->init = TRUE;
4865 if(format == GGO_METRICS)
4867 LeaveCriticalSection( &freetype_cs );
4868 return 1; /* FIXME */
4871 if(ft_face->glyph->format != ft_glyph_format_outline &&
4872 (format == GGO_NATIVE || format == GGO_BEZIER ||
4873 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4874 format == GGO_GRAY8_BITMAP))
4876 TRACE("loaded a bitmap\n");
4877 LeaveCriticalSection( &freetype_cs );
4883 width = lpgm->gmBlackBoxX;
4884 height = lpgm->gmBlackBoxY;
4885 pitch = ((width + 31) >> 5) << 2;
4886 needed = pitch * height;
4888 if(!buf || !buflen) break;
4890 switch(ft_face->glyph->format) {
4891 case ft_glyph_format_bitmap:
4893 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4894 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4895 INT h = ft_face->glyph->bitmap.rows;
4897 memcpy(dst, src, w);
4898 src += ft_face->glyph->bitmap.pitch;
4904 case ft_glyph_format_outline:
4905 ft_bitmap.width = width;
4906 ft_bitmap.rows = height;
4907 ft_bitmap.pitch = pitch;
4908 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4909 ft_bitmap.buffer = buf;
4912 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4914 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4916 /* Note: FreeType will only set 'black' bits for us. */
4917 memset(buf, 0, needed);
4918 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4922 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4923 LeaveCriticalSection( &freetype_cs );
4928 case GGO_GRAY2_BITMAP:
4929 case GGO_GRAY4_BITMAP:
4930 case GGO_GRAY8_BITMAP:
4931 case WINE_GGO_GRAY16_BITMAP:
4933 unsigned int mult, row, col;
4936 width = lpgm->gmBlackBoxX;
4937 height = lpgm->gmBlackBoxY;
4938 pitch = (width + 3) / 4 * 4;
4939 needed = pitch * height;
4941 if(!buf || !buflen) break;
4943 switch(ft_face->glyph->format) {
4944 case ft_glyph_format_bitmap:
4946 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4947 INT h = ft_face->glyph->bitmap.rows;
4949 memset( buf, 0, needed );
4951 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
4952 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
4953 src += ft_face->glyph->bitmap.pitch;
4956 LeaveCriticalSection( &freetype_cs );
4959 case ft_glyph_format_outline:
4961 ft_bitmap.width = width;
4962 ft_bitmap.rows = height;
4963 ft_bitmap.pitch = pitch;
4964 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4965 ft_bitmap.buffer = buf;
4968 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4970 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4972 memset(ft_bitmap.buffer, 0, buflen);
4974 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4976 if(format == GGO_GRAY2_BITMAP)
4978 else if(format == GGO_GRAY4_BITMAP)
4980 else if(format == GGO_GRAY8_BITMAP)
4982 else /* format == WINE_GGO_GRAY16_BITMAP */
4984 LeaveCriticalSection( &freetype_cs );
4990 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4991 LeaveCriticalSection( &freetype_cs );
4996 for(row = 0; row < height; row++) {
4998 for(col = 0; col < width; col++, ptr++) {
4999 *ptr = (((int)*ptr) * mult + 128) / 256;
5006 case WINE_GGO_HRGB_BITMAP:
5007 case WINE_GGO_HBGR_BITMAP:
5008 case WINE_GGO_VRGB_BITMAP:
5009 case WINE_GGO_VBGR_BITMAP:
5010 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5012 switch (ft_face->glyph->format)
5014 case FT_GLYPH_FORMAT_BITMAP:
5019 width = lpgm->gmBlackBoxX;
5020 height = lpgm->gmBlackBoxY;
5022 needed = pitch * height;
5024 if (!buf || !buflen) break;
5026 memset(buf, 0, buflen);
5028 src = ft_face->glyph->bitmap.buffer;
5029 src_pitch = ft_face->glyph->bitmap.pitch;
5031 height = min( height, ft_face->glyph->bitmap.rows );
5034 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5036 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5037 ((unsigned int *)dst)[x] = ~0u;
5046 case FT_GLYPH_FORMAT_OUTLINE:
5050 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5051 INT x_shift, y_shift;
5053 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5054 FT_Render_Mode render_mode =
5055 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5056 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5058 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5060 if ( render_mode == FT_RENDER_MODE_LCD)
5062 lpgm->gmBlackBoxX += 2;
5063 lpgm->gmptGlyphOrigin.x -= 1;
5067 lpgm->gmBlackBoxY += 2;
5068 lpgm->gmptGlyphOrigin.y += 1;
5072 width = lpgm->gmBlackBoxX;
5073 height = lpgm->gmBlackBoxY;
5075 needed = pitch * height;
5077 if (!buf || !buflen) break;
5079 memset(buf, 0, buflen);
5081 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5083 if ( needsTransform )
5084 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5086 if ( pFT_Library_SetLcdFilter )
5087 pFT_Library_SetLcdFilter( library, lcdfilter );
5088 pFT_Render_Glyph (ft_face->glyph, render_mode);
5090 src = ft_face->glyph->bitmap.buffer;
5091 src_pitch = ft_face->glyph->bitmap.pitch;
5092 src_width = ft_face->glyph->bitmap.width;
5093 src_height = ft_face->glyph->bitmap.rows;
5095 if ( render_mode == FT_RENDER_MODE_LCD)
5103 rgb_interval = src_pitch;
5108 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5109 if ( x_shift < 0 ) x_shift = 0;
5110 if ( x_shift + (src_width / hmul) > width )
5111 x_shift = width - (src_width / hmul);
5113 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5114 if ( y_shift < 0 ) y_shift = 0;
5115 if ( y_shift + (src_height / vmul) > height )
5116 y_shift = height - (src_height / vmul);
5118 dst += x_shift + y_shift * ( pitch / 4 );
5119 while ( src_height )
5121 for ( x = 0; x < src_width / hmul; x++ )
5125 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5126 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5127 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5128 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5132 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5133 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5134 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5135 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5138 src += src_pitch * vmul;
5147 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5148 LeaveCriticalSection ( &freetype_cs );
5155 LeaveCriticalSection( &freetype_cs );
5161 int contour, point = 0, first_pt;
5162 FT_Outline *outline = &ft_face->glyph->outline;
5163 TTPOLYGONHEADER *pph;
5165 DWORD pph_start, cpfx, type;
5167 if(buflen == 0) buf = NULL;
5169 if (needsTransform && buf) {
5170 pFT_Outline_Transform(outline, &transMat);
5173 for(contour = 0; contour < outline->n_contours; contour++) {
5175 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5178 pph->dwType = TT_POLYGON_TYPE;
5179 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5181 needed += sizeof(*pph);
5183 while(point <= outline->contours[contour]) {
5184 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5185 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5186 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5190 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5193 } while(point <= outline->contours[contour] &&
5194 (outline->tags[point] & FT_Curve_Tag_On) ==
5195 (outline->tags[point-1] & FT_Curve_Tag_On));
5196 /* At the end of a contour Windows adds the start point, but
5198 if(point > outline->contours[contour] &&
5199 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5201 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5203 } else if(point <= outline->contours[contour] &&
5204 outline->tags[point] & FT_Curve_Tag_On) {
5205 /* add closing pt for bezier */
5207 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5215 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5218 pph->cb = needed - pph_start;
5224 /* Convert the quadratic Beziers to cubic Beziers.
5225 The parametric eqn for a cubic Bezier is, from PLRM:
5226 r(t) = at^3 + bt^2 + ct + r0
5227 with the control points:
5232 A quadratic Beizer has the form:
5233 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5235 So equating powers of t leads to:
5236 r1 = 2/3 p1 + 1/3 p0
5237 r2 = 2/3 p1 + 1/3 p2
5238 and of course r0 = p0, r3 = p2
5241 int contour, point = 0, first_pt;
5242 FT_Outline *outline = &ft_face->glyph->outline;
5243 TTPOLYGONHEADER *pph;
5245 DWORD pph_start, cpfx, type;
5246 FT_Vector cubic_control[4];
5247 if(buflen == 0) buf = NULL;
5249 if (needsTransform && buf) {
5250 pFT_Outline_Transform(outline, &transMat);
5253 for(contour = 0; contour < outline->n_contours; contour++) {
5255 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5258 pph->dwType = TT_POLYGON_TYPE;
5259 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5261 needed += sizeof(*pph);
5263 while(point <= outline->contours[contour]) {
5264 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5265 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5266 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5269 if(type == TT_PRIM_LINE) {
5271 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5275 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5278 /* FIXME: Possible optimization in endpoint calculation
5279 if there are two consecutive curves */
5280 cubic_control[0] = outline->points[point-1];
5281 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5282 cubic_control[0].x += outline->points[point].x + 1;
5283 cubic_control[0].y += outline->points[point].y + 1;
5284 cubic_control[0].x >>= 1;
5285 cubic_control[0].y >>= 1;
5287 if(point+1 > outline->contours[contour])
5288 cubic_control[3] = outline->points[first_pt];
5290 cubic_control[3] = outline->points[point+1];
5291 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5292 cubic_control[3].x += outline->points[point].x + 1;
5293 cubic_control[3].y += outline->points[point].y + 1;
5294 cubic_control[3].x >>= 1;
5295 cubic_control[3].y >>= 1;
5298 /* r1 = 1/3 p0 + 2/3 p1
5299 r2 = 1/3 p2 + 2/3 p1 */
5300 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5301 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5302 cubic_control[2] = cubic_control[1];
5303 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5304 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5305 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5306 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5308 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5309 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5310 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5315 } while(point <= outline->contours[contour] &&
5316 (outline->tags[point] & FT_Curve_Tag_On) ==
5317 (outline->tags[point-1] & FT_Curve_Tag_On));
5318 /* At the end of a contour Windows adds the start point,
5319 but only for Beziers and we've already done that.
5321 if(point <= outline->contours[contour] &&
5322 outline->tags[point] & FT_Curve_Tag_On) {
5323 /* This is the closing pt of a bezier, but we've already
5324 added it, so just inc point and carry on */
5331 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5334 pph->cb = needed - pph_start;
5340 FIXME("Unsupported format %d\n", format);
5341 LeaveCriticalSection( &freetype_cs );
5344 LeaveCriticalSection( &freetype_cs );
5348 static BOOL get_bitmap_text_metrics(GdiFont *font)
5350 FT_Face ft_face = font->ft_face;
5351 #ifdef HAVE_FREETYPE_FTWINFNT_H
5352 FT_WinFNT_HeaderRec winfnt_header;
5354 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5355 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5356 font->potm->otmSize = size;
5358 #define TM font->potm->otmTextMetrics
5359 #ifdef HAVE_FREETYPE_FTWINFNT_H
5360 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5362 TM.tmHeight = winfnt_header.pixel_height;
5363 TM.tmAscent = winfnt_header.ascent;
5364 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5365 TM.tmInternalLeading = winfnt_header.internal_leading;
5366 TM.tmExternalLeading = winfnt_header.external_leading;
5367 TM.tmAveCharWidth = winfnt_header.avg_width;
5368 TM.tmMaxCharWidth = winfnt_header.max_width;
5369 TM.tmWeight = winfnt_header.weight;
5371 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5372 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5373 TM.tmFirstChar = winfnt_header.first_char;
5374 TM.tmLastChar = winfnt_header.last_char;
5375 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5376 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5377 TM.tmItalic = winfnt_header.italic;
5378 TM.tmUnderlined = font->underline;
5379 TM.tmStruckOut = font->strikeout;
5380 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5381 TM.tmCharSet = winfnt_header.charset;
5386 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5387 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5388 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5389 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5390 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5391 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5392 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5393 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5395 TM.tmDigitizedAspectX = 96; /* FIXME */
5396 TM.tmDigitizedAspectY = 96; /* FIXME */
5398 TM.tmLastChar = 255;
5399 TM.tmDefaultChar = 32;
5400 TM.tmBreakChar = 32;
5401 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5402 TM.tmUnderlined = font->underline;
5403 TM.tmStruckOut = font->strikeout;
5404 /* NB inverted meaning of TMPF_FIXED_PITCH */
5405 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5406 TM.tmCharSet = font->charset;
5414 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5416 double scale_x, scale_y;
5420 scale_x = (double)font->aveWidth;
5421 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5424 scale_x = font->scale_y;
5426 scale_x *= fabs(font->font_desc.matrix.eM11);
5427 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5429 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5430 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5432 SCALE_Y(ptm->tmHeight);
5433 SCALE_Y(ptm->tmAscent);
5434 SCALE_Y(ptm->tmDescent);
5435 SCALE_Y(ptm->tmInternalLeading);
5436 SCALE_Y(ptm->tmExternalLeading);
5437 SCALE_Y(ptm->tmOverhang);
5439 SCALE_X(ptm->tmAveCharWidth);
5440 SCALE_X(ptm->tmMaxCharWidth);
5446 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5448 double scale_x, scale_y;
5452 scale_x = (double)font->aveWidth;
5453 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5456 scale_x = font->scale_y;
5458 scale_x *= fabs(font->font_desc.matrix.eM11);
5459 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5461 scale_font_metrics(font, &potm->otmTextMetrics);
5463 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5464 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5466 SCALE_Y(potm->otmAscent);
5467 SCALE_Y(potm->otmDescent);
5468 SCALE_Y(potm->otmLineGap);
5469 SCALE_Y(potm->otmsCapEmHeight);
5470 SCALE_Y(potm->otmsXHeight);
5471 SCALE_Y(potm->otmrcFontBox.top);
5472 SCALE_Y(potm->otmrcFontBox.bottom);
5473 SCALE_X(potm->otmrcFontBox.left);
5474 SCALE_X(potm->otmrcFontBox.right);
5475 SCALE_Y(potm->otmMacAscent);
5476 SCALE_Y(potm->otmMacDescent);
5477 SCALE_Y(potm->otmMacLineGap);
5478 SCALE_X(potm->otmptSubscriptSize.x);
5479 SCALE_Y(potm->otmptSubscriptSize.y);
5480 SCALE_X(potm->otmptSubscriptOffset.x);
5481 SCALE_Y(potm->otmptSubscriptOffset.y);
5482 SCALE_X(potm->otmptSuperscriptSize.x);
5483 SCALE_Y(potm->otmptSuperscriptSize.y);
5484 SCALE_X(potm->otmptSuperscriptOffset.x);
5485 SCALE_Y(potm->otmptSuperscriptOffset.y);
5486 SCALE_Y(potm->otmsStrikeoutSize);
5487 SCALE_Y(potm->otmsStrikeoutPosition);
5488 SCALE_Y(potm->otmsUnderscoreSize);
5489 SCALE_Y(potm->otmsUnderscorePosition);
5495 /*************************************************************
5496 * WineEngGetTextMetrics
5499 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5502 EnterCriticalSection( &freetype_cs );
5504 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5505 if(!get_bitmap_text_metrics(font))
5507 LeaveCriticalSection( &freetype_cs );
5511 /* Make sure that the font has sane width/height ratio */
5514 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5516 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5522 *ptm = font->potm->otmTextMetrics;
5523 scale_font_metrics(font, ptm);
5524 LeaveCriticalSection( &freetype_cs );
5528 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5532 for(i = 0; i < ft_face->num_charmaps; i++)
5534 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5540 /*************************************************************
5541 * WineEngGetOutlineTextMetrics
5544 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5545 OUTLINETEXTMETRICW *potm)
5547 FT_Face ft_face = font->ft_face;
5548 UINT needed, lenfam, lensty, ret;
5550 TT_HoriHeader *pHori;
5551 TT_Postscript *pPost;
5552 FT_Fixed x_scale, y_scale;
5553 WCHAR *family_nameW, *style_nameW;
5554 static const WCHAR spaceW[] = {' ', '\0'};
5556 INT ascent, descent;
5558 TRACE("font=%p\n", font);
5560 if(!FT_IS_SCALABLE(ft_face))
5564 EnterCriticalSection( &freetype_cs );
5567 if(cbSize >= font->potm->otmSize)
5569 memcpy(potm, font->potm, font->potm->otmSize);
5570 scale_outline_font_metrics(font, potm);
5572 LeaveCriticalSection( &freetype_cs );
5573 return font->potm->otmSize;
5577 needed = sizeof(*potm);
5579 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5580 family_nameW = strdupW(font->name);
5582 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5584 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5585 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5586 style_nameW, lensty/sizeof(WCHAR));
5588 /* These names should be read from the TT name table */
5590 /* length of otmpFamilyName */
5593 /* length of otmpFaceName */
5594 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5595 needed += lenfam; /* just the family name */
5597 needed += lenfam + lensty; /* family + " " + style */
5600 /* length of otmpStyleName */
5603 /* length of otmpFullName */
5604 needed += lenfam + lensty;
5607 x_scale = ft_face->size->metrics.x_scale;
5608 y_scale = ft_face->size->metrics.y_scale;
5610 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5612 FIXME("Can't find OS/2 table - not TT font?\n");
5617 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5619 FIXME("Can't find HHEA table - not TT font?\n");
5624 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5626 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",
5627 pOS2->usWinAscent, pOS2->usWinDescent,
5628 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5629 ft_face->ascender, ft_face->descender, ft_face->height,
5630 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5631 ft_face->bbox.yMax, ft_face->bbox.yMin);
5633 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5634 font->potm->otmSize = needed;
5636 #define TM font->potm->otmTextMetrics
5638 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5639 ascent = pHori->Ascender;
5640 descent = -pHori->Descender;
5642 ascent = pOS2->usWinAscent;
5643 descent = pOS2->usWinDescent;
5647 TM.tmAscent = font->yMax;
5648 TM.tmDescent = -font->yMin;
5649 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5651 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5652 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5653 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5654 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5657 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5660 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5662 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5663 ((ascent + descent) -
5664 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5666 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5667 if (TM.tmAveCharWidth == 0) {
5668 TM.tmAveCharWidth = 1;
5670 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5671 TM.tmWeight = FW_REGULAR;
5672 if (font->fake_bold)
5673 TM.tmWeight = FW_BOLD;
5676 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5678 if (pOS2->usWeightClass > FW_MEDIUM)
5679 TM.tmWeight = pOS2->usWeightClass;
5681 else if (pOS2->usWeightClass <= FW_MEDIUM)
5682 TM.tmWeight = pOS2->usWeightClass;
5685 TM.tmDigitizedAspectX = 300;
5686 TM.tmDigitizedAspectY = 300;
5687 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5688 * symbol range to 0 - f0ff
5691 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5696 case 1257: /* Baltic */
5697 TM.tmLastChar = 0xf8fd;
5700 TM.tmLastChar = 0xf0ff;
5702 TM.tmBreakChar = 0x20;
5703 TM.tmDefaultChar = 0x1f;
5707 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5708 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5710 if(pOS2->usFirstCharIndex <= 1)
5711 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5712 else if (pOS2->usFirstCharIndex > 0xff)
5713 TM.tmBreakChar = 0x20;
5715 TM.tmBreakChar = pOS2->usFirstCharIndex;
5716 TM.tmDefaultChar = TM.tmBreakChar - 1;
5718 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5719 TM.tmUnderlined = font->underline;
5720 TM.tmStruckOut = font->strikeout;
5722 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5723 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5724 (pOS2->version == 0xFFFFU ||
5725 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5726 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5728 TM.tmPitchAndFamily = 0;
5730 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5732 case PAN_FAMILY_SCRIPT:
5733 TM.tmPitchAndFamily |= FF_SCRIPT;
5736 case PAN_FAMILY_DECORATIVE:
5737 TM.tmPitchAndFamily |= FF_DECORATIVE;
5742 case PAN_FAMILY_TEXT_DISPLAY:
5743 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5744 /* which is clearly not what the panose spec says. */
5746 if(TM.tmPitchAndFamily == 0 || /* fixed */
5747 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5748 TM.tmPitchAndFamily = FF_MODERN;
5751 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5756 TM.tmPitchAndFamily |= FF_DONTCARE;
5759 case PAN_SERIF_COVE:
5760 case PAN_SERIF_OBTUSE_COVE:
5761 case PAN_SERIF_SQUARE_COVE:
5762 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5763 case PAN_SERIF_SQUARE:
5764 case PAN_SERIF_THIN:
5765 case PAN_SERIF_BONE:
5766 case PAN_SERIF_EXAGGERATED:
5767 case PAN_SERIF_TRIANGLE:
5768 TM.tmPitchAndFamily |= FF_ROMAN;
5771 case PAN_SERIF_NORMAL_SANS:
5772 case PAN_SERIF_OBTUSE_SANS:
5773 case PAN_SERIF_PERP_SANS:
5774 case PAN_SERIF_FLARED:
5775 case PAN_SERIF_ROUNDED:
5776 TM.tmPitchAndFamily |= FF_SWISS;
5783 if(FT_IS_SCALABLE(ft_face))
5784 TM.tmPitchAndFamily |= TMPF_VECTOR;
5786 if(FT_IS_SFNT(ft_face))
5788 if (font->ntmFlags & NTM_PS_OPENTYPE)
5789 TM.tmPitchAndFamily |= TMPF_DEVICE;
5791 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5794 TM.tmCharSet = font->charset;
5796 font->potm->otmFiller = 0;
5797 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5798 font->potm->otmfsSelection = pOS2->fsSelection;
5799 font->potm->otmfsType = pOS2->fsType;
5800 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5801 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5802 font->potm->otmItalicAngle = 0; /* POST table */
5803 font->potm->otmEMSquare = ft_face->units_per_EM;
5804 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5805 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5806 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5807 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5808 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5809 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5810 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5811 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5812 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5813 font->potm->otmMacAscent = TM.tmAscent;
5814 font->potm->otmMacDescent = -TM.tmDescent;
5815 font->potm->otmMacLineGap = font->potm->otmLineGap;
5816 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5817 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5818 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5819 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5820 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5821 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5822 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5823 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5824 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5825 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5826 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5828 font->potm->otmsUnderscoreSize = 0;
5829 font->potm->otmsUnderscorePosition = 0;
5831 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5832 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5836 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5837 cp = (char*)font->potm + sizeof(*font->potm);
5838 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5839 strcpyW((WCHAR*)cp, family_nameW);
5841 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5842 strcpyW((WCHAR*)cp, style_nameW);
5844 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5845 strcpyW((WCHAR*)cp, family_nameW);
5846 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5847 strcatW((WCHAR*)cp, spaceW);
5848 strcatW((WCHAR*)cp, style_nameW);
5849 cp += lenfam + lensty;
5852 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5853 strcpyW((WCHAR*)cp, family_nameW);
5854 strcatW((WCHAR*)cp, spaceW);
5855 strcatW((WCHAR*)cp, style_nameW);
5858 if(potm && needed <= cbSize)
5860 memcpy(potm, font->potm, font->potm->otmSize);
5861 scale_outline_font_metrics(font, potm);
5865 HeapFree(GetProcessHeap(), 0, style_nameW);
5866 HeapFree(GetProcessHeap(), 0, family_nameW);
5868 LeaveCriticalSection( &freetype_cs );
5872 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5874 HFONTLIST *hfontlist;
5875 child->font = alloc_font();
5876 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5877 if(!child->font->ft_face)
5879 free_font(child->font);
5884 child->font->font_desc = font->font_desc;
5885 child->font->ntmFlags = child->face->ntmFlags;
5886 child->font->orientation = font->orientation;
5887 child->font->scale_y = font->scale_y;
5888 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5889 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5890 child->font->name = strdupW(child->face->family->FamilyName);
5891 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5892 child->font->base_font = font;
5893 list_add_head(&child_font_list, &child->font->entry);
5894 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5898 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5901 CHILD_FONT *child_font;
5904 font = font->base_font;
5906 *linked_font = font;
5908 if((*glyph = get_glyph_index(font, c)))
5911 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5913 if(!child_font->font)
5914 if(!load_child_font(font, child_font))
5917 if(!child_font->font->ft_face)
5919 g = get_glyph_index(child_font->font, c);
5923 *linked_font = child_font->font;
5930 /*************************************************************
5931 * WineEngGetCharWidth
5934 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5937 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5940 FT_UInt glyph_index;
5941 GdiFont *linked_font;
5943 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5946 EnterCriticalSection( &freetype_cs );
5947 for(c = firstChar; c <= lastChar; c++) {
5948 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5949 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5950 &gm, 0, NULL, &identity);
5951 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5953 LeaveCriticalSection( &freetype_cs );
5957 /*************************************************************
5958 * WineEngGetCharABCWidths
5961 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5964 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5967 FT_UInt glyph_index;
5968 GdiFont *linked_font;
5970 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5972 if(!FT_IS_SCALABLE(font->ft_face))
5976 EnterCriticalSection( &freetype_cs );
5978 for(c = firstChar; c <= lastChar; c++) {
5979 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5980 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5981 &gm, 0, NULL, &identity);
5982 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5983 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5984 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5985 FONT_GM(linked_font,glyph_index)->bbx;
5987 LeaveCriticalSection( &freetype_cs );
5991 /*************************************************************
5992 * WineEngGetCharABCWidthsFloat
5995 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
5997 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6000 FT_UInt glyph_index;
6001 GdiFont *linked_font;
6003 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6006 EnterCriticalSection( &freetype_cs );
6008 for (c = first; c <= last; c++)
6010 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6011 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6012 &gm, 0, NULL, &identity);
6013 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6014 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6015 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6016 FONT_GM(linked_font, glyph_index)->lsb -
6017 FONT_GM(linked_font, glyph_index)->bbx;
6019 LeaveCriticalSection( &freetype_cs );
6023 /*************************************************************
6024 * WineEngGetCharABCWidthsI
6027 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6030 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6033 FT_UInt glyph_index;
6034 GdiFont *linked_font;
6036 if(!FT_HAS_HORIZONTAL(font->ft_face))
6040 EnterCriticalSection( &freetype_cs );
6042 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6044 for(c = firstChar; c < firstChar+count; c++) {
6045 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6046 &gm, 0, NULL, &identity);
6047 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6048 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6049 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6050 - FONT_GM(linked_font,c)->bbx;
6053 for(c = 0; c < count; c++) {
6054 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6055 &gm, 0, NULL, &identity);
6056 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6057 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6058 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6059 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6062 LeaveCriticalSection( &freetype_cs );
6066 /*************************************************************
6067 * WineEngGetTextExtentExPoint
6070 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6071 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6073 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6078 FT_UInt glyph_index;
6079 GdiFont *linked_font;
6081 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6085 EnterCriticalSection( &freetype_cs );
6088 WineEngGetTextMetrics(font, &tm);
6089 size->cy = tm.tmHeight;
6091 for(idx = 0; idx < count; idx++) {
6092 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6093 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6094 &gm, 0, NULL, &identity);
6095 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6097 if (! pnfit || ext <= max_ext) {
6107 LeaveCriticalSection( &freetype_cs );
6108 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6112 /*************************************************************
6113 * WineEngGetTextExtentExPointI
6116 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6117 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6119 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6125 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6128 EnterCriticalSection( &freetype_cs );
6131 WineEngGetTextMetrics(font, &tm);
6132 size->cy = tm.tmHeight;
6134 for(idx = 0; idx < count; idx++) {
6135 WineEngGetGlyphOutline(font, indices[idx],
6136 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6138 size->cx += FONT_GM(font,indices[idx])->adv;
6140 if (! pnfit || ext <= max_ext) {
6150 LeaveCriticalSection( &freetype_cs );
6151 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6155 /*************************************************************
6156 * WineEngGetFontData
6159 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6162 FT_Face ft_face = font->ft_face;
6166 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6167 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6168 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6170 if(!FT_IS_SFNT(ft_face))
6178 if(table) { /* MS tags differ in endianness from FT ones */
6179 table = table >> 24 | table << 24 |
6180 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6183 /* make sure value of len is the value freetype says it needs */
6186 FT_ULong needed = 0;
6187 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6188 if( !err && needed < len) len = needed;
6190 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6193 TRACE("Can't find table %c%c%c%c\n",
6194 /* bytes were reversed */
6195 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6196 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6202 /*************************************************************
6203 * WineEngGetTextFace
6206 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6208 INT n = strlenW(font->name) + 1;
6210 lstrcpynW(str, font->name, count);
6211 return min(count, n);
6216 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6218 if (fs) *fs = font->fs;
6219 return font->charset;
6222 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6224 GdiFont *font = dc->gdiFont, *linked_font;
6225 struct list *first_hfont;
6229 EnterCriticalSection( &freetype_cs );
6230 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6231 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6232 if(font == linked_font)
6233 *new_hfont = dc->hFont;
6236 first_hfont = list_head(&linked_font->hfontlist);
6237 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6239 LeaveCriticalSection( &freetype_cs );
6243 /* Retrieve a list of supported Unicode ranges for a given font.
6244 * Can be called with NULL gs to calculate the buffer size. Returns
6245 * the number of ranges found.
6247 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6249 DWORD num_ranges = 0;
6251 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6254 FT_ULong char_code, char_code_prev;
6257 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6259 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6260 face->num_glyphs, glyph_code, char_code);
6262 if (!glyph_code) return 0;
6266 gs->ranges[0].wcLow = (USHORT)char_code;
6267 gs->ranges[0].cGlyphs = 0;
6268 gs->cGlyphsSupported = 0;
6274 if (char_code < char_code_prev)
6276 ERR("expected increasing char code from FT_Get_Next_Char\n");
6279 if (char_code - char_code_prev > 1)
6284 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6285 gs->ranges[num_ranges - 1].cGlyphs = 1;
6286 gs->cGlyphsSupported++;
6291 gs->ranges[num_ranges - 1].cGlyphs++;
6292 gs->cGlyphsSupported++;
6294 char_code_prev = char_code;
6295 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6299 FIXME("encoding %u not supported\n", face->charmap->encoding);
6304 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6307 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6309 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6312 glyphset->cbThis = size;
6313 glyphset->cRanges = num_ranges;
6314 glyphset->flAccel = 0;
6319 /*************************************************************
6322 BOOL WineEngFontIsLinked(GdiFont *font)
6326 EnterCriticalSection( &freetype_cs );
6327 ret = !list_empty(&font->child_fonts);
6328 LeaveCriticalSection( &freetype_cs );
6332 static BOOL is_hinting_enabled(void)
6334 /* Use the >= 2.2.0 function if available */
6335 if(pFT_Get_TrueType_Engine_Type)
6337 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6338 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6340 #ifdef FT_DRIVER_HAS_HINTER
6345 /* otherwise if we've been compiled with < 2.2.0 headers
6346 use the internal macro */
6347 mod = pFT_Get_Module(library, "truetype");
6348 if(mod && FT_DRIVER_HAS_HINTER(mod))
6356 static BOOL is_subpixel_rendering_enabled( void )
6358 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6359 return pFT_Library_SetLcdFilter &&
6360 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6366 /*************************************************************************
6367 * GetRasterizerCaps (GDI32.@)
6369 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6371 static int hinting = -1;
6372 static int subpixel = -1;
6376 hinting = is_hinting_enabled();
6377 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6380 if ( subpixel == -1 )
6382 subpixel = is_subpixel_rendering_enabled();
6383 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6386 lprs->nSize = sizeof(RASTERIZER_STATUS);
6387 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6389 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6390 lprs->nLanguageID = 0;
6394 /*************************************************************
6395 * WineEngRealizationInfo
6397 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6399 FIXME("(%p, %p): stub!\n", font, info);
6402 if(FT_IS_SCALABLE(font->ft_face))
6405 info->cache_num = font->cache_num;
6406 info->unknown2 = -1;
6410 /*************************************************************************
6411 * Kerning support for TrueType fonts
6413 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6415 struct TT_kern_table
6421 struct TT_kern_subtable
6430 USHORT horizontal : 1;
6432 USHORT cross_stream: 1;
6433 USHORT override : 1;
6434 USHORT reserved1 : 4;
6440 struct TT_format0_kern_subtable
6444 USHORT entrySelector;
6455 static DWORD parse_format0_kern_subtable(GdiFont *font,
6456 const struct TT_format0_kern_subtable *tt_f0_ks,
6457 const USHORT *glyph_to_char,
6458 KERNINGPAIR *kern_pair, DWORD cPairs)
6461 const struct TT_kern_pair *tt_kern_pair;
6463 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6465 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6467 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6468 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6469 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6471 if (!kern_pair || !cPairs)
6474 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6476 nPairs = min(nPairs, cPairs);
6478 for (i = 0; i < nPairs; i++)
6480 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6481 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6482 /* this algorithm appears to better match what Windows does */
6483 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6484 if (kern_pair->iKernAmount < 0)
6486 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6487 kern_pair->iKernAmount -= font->ppem;
6489 else if (kern_pair->iKernAmount > 0)
6491 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6492 kern_pair->iKernAmount += font->ppem;
6494 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6496 TRACE("left %u right %u value %d\n",
6497 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6501 TRACE("copied %u entries\n", nPairs);
6505 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6509 const struct TT_kern_table *tt_kern_table;
6510 const struct TT_kern_subtable *tt_kern_subtable;
6512 USHORT *glyph_to_char;
6515 EnterCriticalSection( &freetype_cs );
6516 if (font->total_kern_pairs != (DWORD)-1)
6518 if (cPairs && kern_pair)
6520 cPairs = min(cPairs, font->total_kern_pairs);
6521 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6522 LeaveCriticalSection( &freetype_cs );
6525 LeaveCriticalSection( &freetype_cs );
6526 return font->total_kern_pairs;
6529 font->total_kern_pairs = 0;
6531 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6533 if (length == GDI_ERROR)
6535 TRACE("no kerning data in the font\n");
6536 LeaveCriticalSection( &freetype_cs );
6540 buf = HeapAlloc(GetProcessHeap(), 0, length);
6543 WARN("Out of memory\n");
6544 LeaveCriticalSection( &freetype_cs );
6548 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6550 /* build a glyph index to char code map */
6551 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6554 WARN("Out of memory allocating a glyph index to char code map\n");
6555 HeapFree(GetProcessHeap(), 0, buf);
6556 LeaveCriticalSection( &freetype_cs );
6560 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6566 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6568 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6569 font->ft_face->num_glyphs, glyph_code, char_code);
6573 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6575 /* FIXME: This doesn't match what Windows does: it does some fancy
6576 * things with duplicate glyph index to char code mappings, while
6577 * we just avoid overriding existing entries.
6579 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6580 glyph_to_char[glyph_code] = (USHORT)char_code;
6582 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6589 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6590 for (n = 0; n <= 65535; n++)
6591 glyph_to_char[n] = (USHORT)n;
6594 tt_kern_table = buf;
6595 nTables = GET_BE_WORD(tt_kern_table->nTables);
6596 TRACE("version %u, nTables %u\n",
6597 GET_BE_WORD(tt_kern_table->version), nTables);
6599 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6601 for (i = 0; i < nTables; i++)
6603 struct TT_kern_subtable tt_kern_subtable_copy;
6605 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6606 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6607 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6609 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6610 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6611 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6613 /* According to the TrueType specification this is the only format
6614 * that will be properly interpreted by Windows and OS/2
6616 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6618 DWORD new_chunk, old_total = font->total_kern_pairs;
6620 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6621 glyph_to_char, NULL, 0);
6622 font->total_kern_pairs += new_chunk;
6624 if (!font->kern_pairs)
6625 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6626 font->total_kern_pairs * sizeof(*font->kern_pairs));
6628 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6629 font->total_kern_pairs * sizeof(*font->kern_pairs));
6631 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6632 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6635 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6637 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6640 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6641 HeapFree(GetProcessHeap(), 0, buf);
6643 if (cPairs && kern_pair)
6645 cPairs = min(cPairs, font->total_kern_pairs);
6646 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6647 LeaveCriticalSection( &freetype_cs );
6650 LeaveCriticalSection( &freetype_cs );
6651 return font->total_kern_pairs;
6654 #else /* HAVE_FREETYPE */
6656 /*************************************************************************/
6658 BOOL WineEngInit(void)
6662 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6666 BOOL WineEngDestroyFontInstance(HFONT hfont)
6671 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6676 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6677 LPWORD pgi, DWORD flags)
6682 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6683 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6686 ERR("called but we don't have FreeType\n");
6690 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6692 ERR("called but we don't have FreeType\n");
6696 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6697 OUTLINETEXTMETRICW *potm)
6699 ERR("called but we don't have FreeType\n");
6703 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6706 ERR("called but we don't have FreeType\n");
6710 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6713 ERR("called but we don't have FreeType\n");
6717 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6719 ERR("called but we don't have FreeType\n");
6723 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6726 ERR("called but we don't have FreeType\n");
6730 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6731 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6733 ERR("called but we don't have FreeType\n");
6737 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6738 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6740 ERR("called but we don't have FreeType\n");
6744 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6747 ERR("called but we don't have FreeType\n");
6751 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6753 ERR("called but we don't have FreeType\n");
6757 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6759 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6763 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6765 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6769 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6771 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6775 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6777 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6778 return DEFAULT_CHARSET;
6781 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6786 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6788 FIXME("(%p, %p): stub\n", font, glyphset);
6792 BOOL WineEngFontIsLinked(GdiFont *font)
6797 /*************************************************************************
6798 * GetRasterizerCaps (GDI32.@)
6800 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6802 lprs->nSize = sizeof(RASTERIZER_STATUS);
6804 lprs->nLanguageID = 0;
6808 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6810 ERR("called but we don't have FreeType\n");
6814 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6816 ERR("called but we don't have FreeType\n");
6820 #endif /* HAVE_FREETYPE */