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 {
265 const WCHAR *FullName;
268 DWORD font_data_size;
271 FONTSIGNATURE fs_links;
273 FT_Fixed font_version;
275 Bitmap_Size size; /* set if face is a bitmap */
276 BOOL external; /* TRUE if we should manually add this font to the registry */
277 struct tagFamily *family;
278 /* Cached data for Enum */
279 struct enum_data *cached_enum_data;
282 typedef struct tagFamily {
284 const WCHAR *FamilyName;
290 INT adv; /* These three hold to widths of the unrotated chars */
308 typedef struct tagHFONTLIST {
323 struct list hfontlist;
324 OUTLINETEXTMETRICW *potm;
325 DWORD total_kern_pairs;
326 KERNINGPAIR *kern_pairs;
327 struct list child_fonts;
329 /* the following members can be accessed without locking, they are never modified after creation */
331 struct font_mapping *mapping;
354 const WCHAR *font_name;
358 struct enum_charset_element {
364 struct enum_charset_list {
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
383 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
384 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
386 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
387 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
388 'W','i','n','d','o','w','s','\\',
389 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
390 'F','o','n','t','s','\0'};
392 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
393 'W','i','n','d','o','w','s',' ','N','T','\\',
394 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
395 'F','o','n','t','s','\0'};
397 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
398 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
399 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
400 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
402 static const WCHAR * const SystemFontValues[4] = {
409 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
410 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
412 /* Interesting and well-known (frequently-assumed!) font names */
413 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
414 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 };
415 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
416 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
417 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
418 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
419 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
420 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
422 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
423 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
424 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
425 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
426 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
427 'E','u','r','o','p','e','a','n','\0'};
428 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
429 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
430 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
431 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
432 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
433 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
434 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
435 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
436 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
437 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
438 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
439 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
441 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
451 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
459 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
468 typedef struct tagFontSubst {
484 static struct list mappings_list = LIST_INIT( mappings_list );
486 static CRITICAL_SECTION freetype_cs;
487 static CRITICAL_SECTION_DEBUG critsect_debug =
490 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
491 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
493 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
495 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
497 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
498 static BOOL use_default_fallback = FALSE;
500 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
502 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
503 'W','i','n','d','o','w','s',' ','N','T','\\',
504 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
505 'S','y','s','t','e','m','L','i','n','k',0};
507 /****************************************
508 * Notes on .fon files
510 * The fonts System, FixedSys and Terminal are special. There are typically multiple
511 * versions installed for different resolutions and codepages. Windows stores which one to use
512 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
514 * FIXEDFON.FON FixedSys
516 * OEMFONT.FON Terminal
517 * LogPixels Current dpi set by the display control panel applet
518 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
519 * also has a LogPixels value that appears to mirror this)
521 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
522 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
523 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
524 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
525 * so that makes sense.
527 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
528 * to be mapped into the registry on Windows 2000 at least).
531 * ega80woa.fon=ega80850.fon
532 * ega40woa.fon=ega40850.fon
533 * cga80woa.fon=cga80850.fon
534 * cga40woa.fon=cga40850.fon
537 /* These are all structures needed for the GSUB table */
539 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
540 #define TATEGAKI_LOWER_BOUND 0x02F1
556 GSUB_ScriptRecord ScriptRecord[1];
562 } GSUB_LangSysRecord;
567 GSUB_LangSysRecord LangSysRecord[1];
571 WORD LookupOrder; /* Reserved */
572 WORD ReqFeatureIndex;
574 WORD FeatureIndex[1];
580 } GSUB_FeatureRecord;
584 GSUB_FeatureRecord FeatureRecord[1];
588 WORD FeatureParams; /* Reserved */
590 WORD LookupListIndex[1];
609 } GSUB_CoverageFormat1;
614 WORD StartCoverageIndex;
620 GSUB_RangeRecord RangeRecord[1];
621 } GSUB_CoverageFormat2;
624 WORD SubstFormat; /* = 1 */
627 } GSUB_SingleSubstFormat1;
630 WORD SubstFormat; /* = 2 */
634 }GSUB_SingleSubstFormat2;
636 #ifdef HAVE_CARBON_CARBON_H
637 static char *find_cache_dir(void)
641 static char cached_path[MAX_PATH];
642 static const char *wine = "/Wine", *fonts = "/Fonts";
644 if(*cached_path) return cached_path;
646 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
649 WARN("can't create cached data folder\n");
652 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
655 WARN("can't create cached data path\n");
659 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
661 ERR("Could not create full path\n");
665 strcat(cached_path, wine);
667 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
669 WARN("Couldn't mkdir %s\n", cached_path);
673 strcat(cached_path, fonts);
674 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
676 WARN("Couldn't mkdir %s\n", cached_path);
683 /******************************************************************
686 * Extracts individual TrueType font files from a Mac suitcase font
687 * and saves them into the user's caches directory (see
689 * Returns a NULL terminated array of filenames.
691 * We do this because they are apps that try to read ttf files
692 * themselves and they don't like Mac suitcase files.
694 static char **expand_mac_font(const char *path)
701 const char *filename;
705 unsigned int size, max_size;
708 TRACE("path %s\n", path);
710 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
713 WARN("failed to get ref\n");
717 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
720 TRACE("no data fork, so trying resource fork\n");
721 res_ref = FSOpenResFile(&ref, fsRdPerm);
724 TRACE("unable to open resource fork\n");
731 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
734 CloseResFile(res_ref);
738 out_dir = find_cache_dir();
740 filename = strrchr(path, '/');
741 if(!filename) filename = path;
744 /* output filename has the form out_dir/filename_%04x.ttf */
745 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
752 unsigned short *num_faces_ptr, num_faces, face;
755 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
757 fond = Get1IndResource(fond_res, idx);
759 TRACE("got fond resource %d\n", idx);
762 fam_rec = *(FamRec**)fond;
763 num_faces_ptr = (unsigned short *)(fam_rec + 1);
764 num_faces = GET_BE_WORD(*num_faces_ptr);
766 assoc = (AsscEntry*)(num_faces_ptr + 1);
767 TRACE("num faces %04x\n", num_faces);
768 for(face = 0; face < num_faces; face++, assoc++)
771 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
772 unsigned short size, font_id;
775 size = GET_BE_WORD(assoc->fontSize);
776 font_id = GET_BE_WORD(assoc->fontID);
779 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
783 TRACE("trying to load sfnt id %04x\n", font_id);
784 sfnt = GetResource(sfnt_res, font_id);
787 TRACE("can't get sfnt resource %04x\n", font_id);
791 output = HeapAlloc(GetProcessHeap(), 0, output_len);
796 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
798 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
799 if(fd != -1 || errno == EEXIST)
803 unsigned char *sfnt_data;
806 sfnt_data = *(unsigned char**)sfnt;
807 write(fd, sfnt_data, GetHandleSize(sfnt));
811 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
814 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
816 ret.array[ret.size++] = output;
820 WARN("unable to create %s\n", output);
821 HeapFree(GetProcessHeap(), 0, output);
824 ReleaseResource(sfnt);
827 ReleaseResource(fond);
830 CloseResFile(res_ref);
835 #endif /* HAVE_CARBON_CARBON_H */
837 static inline BOOL is_win9x(void)
839 return GetVersion() & 0x80000000;
842 This function builds an FT_Fixed from a double. It fails if the absolute
843 value of the float number is greater than 32768.
845 static inline FT_Fixed FT_FixedFromFloat(double f)
851 This function builds an FT_Fixed from a FIXED. It simply put f.value
852 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
854 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
856 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
860 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
865 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
866 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
868 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
869 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
871 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
873 if(face_name && strcmpiW(face_name, family->FamilyName))
875 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
879 file = strrchr(face->file, '/');
884 if(!strcasecmp(file, file_nameA))
886 HeapFree(GetProcessHeap(), 0, file_nameA);
891 HeapFree(GetProcessHeap(), 0, file_nameA);
895 static Family *find_family_from_name(const WCHAR *name)
899 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
901 if(!strcmpiW(family->FamilyName, name))
908 static void DumpSubstList(void)
912 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
914 if(psub->from.charset != -1 || psub->to.charset != -1)
915 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
916 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
918 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
919 debugstr_w(psub->to.name));
924 static LPWSTR strdupW(LPCWSTR p)
927 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
928 ret = HeapAlloc(GetProcessHeap(), 0, len);
933 static LPSTR strdupA(LPCSTR p)
936 DWORD len = (strlen(p) + 1);
937 ret = HeapAlloc(GetProcessHeap(), 0, len);
942 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
947 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
949 if(!strcmpiW(element->from.name, from_name) &&
950 (element->from.charset == from_charset ||
951 element->from.charset == -1))
958 #define ADD_FONT_SUBST_FORCE 1
960 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
962 FontSubst *from_exist, *to_exist;
964 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
966 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
968 list_remove(&from_exist->entry);
969 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
970 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
971 HeapFree(GetProcessHeap(), 0, from_exist);
977 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
981 HeapFree(GetProcessHeap(), 0, subst->to.name);
982 subst->to.name = strdupW(to_exist->to.name);
985 list_add_tail(subst_list, &subst->entry);
990 HeapFree(GetProcessHeap(), 0, subst->from.name);
991 HeapFree(GetProcessHeap(), 0, subst->to.name);
992 HeapFree(GetProcessHeap(), 0, subst);
996 static void split_subst_info(NameCs *nc, LPSTR str)
998 CHAR *p = strrchr(str, ',');
1003 nc->charset = strtol(p+1, NULL, 10);
1006 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1007 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1008 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1011 static void LoadSubstList(void)
1015 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1019 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1020 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1021 &hkey) == ERROR_SUCCESS) {
1023 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1024 &valuelen, &datalen, NULL, NULL);
1026 valuelen++; /* returned value doesn't include room for '\0' */
1027 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1028 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1032 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1033 &dlen) == ERROR_SUCCESS) {
1034 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1036 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1037 split_subst_info(&psub->from, value);
1038 split_subst_info(&psub->to, data);
1040 /* Win 2000 doesn't allow mapping between different charsets
1041 or mapping of DEFAULT_CHARSET */
1042 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1043 psub->to.charset == DEFAULT_CHARSET) {
1044 HeapFree(GetProcessHeap(), 0, psub->to.name);
1045 HeapFree(GetProcessHeap(), 0, psub->from.name);
1046 HeapFree(GetProcessHeap(), 0, psub);
1048 add_font_subst(&font_subst_list, psub, 0);
1050 /* reset dlen and vlen */
1054 HeapFree(GetProcessHeap(), 0, data);
1055 HeapFree(GetProcessHeap(), 0, value);
1061 /*****************************************************************
1062 * get_name_table_entry
1064 * Supply the platform, encoding, language and name ids in req
1065 * and if the name exists the function will fill in the string
1066 * and string_len members. The string is owned by FreeType so
1067 * don't free it. Returns TRUE if the name is found else FALSE.
1069 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1072 FT_UInt num_names, name_index;
1074 if(FT_IS_SFNT(ft_face))
1076 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1078 for(name_index = 0; name_index < num_names; name_index++)
1080 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1082 if((name.platform_id == req->platform_id) &&
1083 (name.encoding_id == req->encoding_id) &&
1084 (name.language_id == req->language_id) &&
1085 (name.name_id == req->name_id))
1087 req->string = name.string;
1088 req->string_len = name.string_len;
1095 req->string_len = 0;
1099 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1104 name.platform_id = TT_PLATFORM_MICROSOFT;
1105 name.encoding_id = TT_MS_ID_UNICODE_CS;
1106 name.language_id = language_id;
1107 name.name_id = name_id;
1109 if(get_name_table_entry(ft_face, &name))
1113 /* String is not nul terminated and string_len is a byte length. */
1114 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1115 for(i = 0; i < name.string_len / 2; i++)
1117 WORD *tmp = (WORD *)&name.string[i * 2];
1118 ret[i] = GET_BE_WORD(*tmp);
1121 TRACE("Got localised name %s\n", debugstr_w(ret));
1128 /*****************************************************************
1131 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1132 * of FreeType that don't export this function.
1135 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1140 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1141 if(pFT_Load_Sfnt_Table)
1143 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1145 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1146 else /* Do it the hard way */
1148 TT_Face tt_face = (TT_Face) ft_face;
1149 SFNT_Interface *sfnt;
1150 if (FT_Version.major==2 && FT_Version.minor==0)
1153 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1157 /* A field was added in the middle of the structure in 2.1.x */
1158 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1160 err = sfnt->load_any(tt_face, table, offset, buf, len);
1168 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1169 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1170 "Please upgrade your freetype library.\n");
1173 err = FT_Err_Unimplemented_Feature;
1179 static inline int TestStyles(DWORD flags, DWORD styles)
1181 return (flags & styles) == styles;
1184 static int StyleOrdering(Face *face)
1186 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1188 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1190 if (TestStyles(face->ntmFlags, NTM_BOLD))
1192 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1195 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1196 debugstr_w(face->family->FamilyName),
1197 debugstr_w(face->StyleName),
1203 /* Add a style of face to a font family using an ordering of the list such
1204 that regular fonts come before bold and italic, and single styles come
1205 before compound styles. */
1206 static void AddFaceToFamily(Face *face, Family *family)
1210 LIST_FOR_EACH( entry, &family->faces )
1212 Face *ent = LIST_ENTRY(entry, Face, entry);
1213 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1215 list_add_before( entry, &face->entry );
1218 #define ADDFONT_EXTERNAL_FONT 0x01
1219 #define ADDFONT_FORCE_BITMAP 0x02
1220 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1224 TT_Header *pHeader = NULL;
1225 WCHAR *english_family, *localised_family, *StyleW;
1229 struct list *family_elem_ptr, *face_elem_ptr;
1231 FT_Long face_index = 0, num_faces;
1232 #ifdef HAVE_FREETYPE_FTWINFNT_H
1233 FT_WinFNT_HeaderRec winfnt_header;
1235 int i, bitmap_num, internal_leading;
1238 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1239 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1241 #ifdef HAVE_CARBON_CARBON_H
1242 if(file && !fake_family)
1244 char **mac_list = expand_mac_font(file);
1247 BOOL had_one = FALSE;
1249 for(cursor = mac_list; *cursor; cursor++)
1252 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1253 HeapFree(GetProcessHeap(), 0, *cursor);
1255 HeapFree(GetProcessHeap(), 0, mac_list);
1260 #endif /* HAVE_CARBON_CARBON_H */
1263 char *family_name = fake_family;
1267 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1268 err = pFT_New_Face(library, file, face_index, &ft_face);
1271 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1272 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1276 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1280 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*/
1281 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1282 pFT_Done_Face(ft_face);
1286 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1287 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1288 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1289 pFT_Done_Face(ft_face);
1293 if(FT_IS_SFNT(ft_face))
1295 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1296 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1297 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1299 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1300 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1301 pFT_Done_Face(ft_face);
1305 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1306 we don't want to load these. */
1307 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1311 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1313 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1314 pFT_Done_Face(ft_face);
1320 if(!ft_face->family_name || !ft_face->style_name) {
1321 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1322 pFT_Done_Face(ft_face);
1326 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1328 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1329 pFT_Done_Face(ft_face);
1335 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1336 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1338 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1339 HeapFree(GetProcessHeap(), 0, localised_family);
1340 num_faces = ft_face->num_faces;
1341 pFT_Done_Face(ft_face);
1344 HeapFree(GetProcessHeap(), 0, localised_family);
1348 family_name = ft_face->family_name;
1352 My_FT_Bitmap_Size *size = NULL;
1355 if(!FT_IS_SCALABLE(ft_face))
1356 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1358 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1359 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1360 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1362 localised_family = NULL;
1364 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1365 if(localised_family && !strcmpiW(localised_family, english_family)) {
1366 HeapFree(GetProcessHeap(), 0, localised_family);
1367 localised_family = NULL;
1372 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1373 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1374 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1379 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1380 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1381 list_init(&family->faces);
1382 list_add_tail(&font_list, &family->entry);
1384 if(localised_family) {
1385 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1386 subst->from.name = strdupW(english_family);
1387 subst->from.charset = -1;
1388 subst->to.name = strdupW(localised_family);
1389 subst->to.charset = -1;
1390 add_font_subst(&font_subst_list, subst, 0);
1393 HeapFree(GetProcessHeap(), 0, localised_family);
1394 HeapFree(GetProcessHeap(), 0, english_family);
1396 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1397 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1398 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1400 internal_leading = 0;
1401 memset(&fs, 0, sizeof(fs));
1403 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1405 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1406 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1407 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1408 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1409 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1410 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1411 if(pOS2->version == 0) {
1414 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1415 fs.fsCsb[0] |= FS_LATIN1;
1417 fs.fsCsb[0] |= FS_SYMBOL;
1420 #ifdef HAVE_FREETYPE_FTWINFNT_H
1421 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1423 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1424 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1425 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1427 internal_leading = winfnt_header.internal_leading;
1431 face_elem_ptr = list_head(&family->faces);
1432 while(face_elem_ptr) {
1433 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1434 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1435 if(!strcmpiW(face->StyleName, StyleW) &&
1436 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1437 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1438 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1439 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1442 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1443 HeapFree(GetProcessHeap(), 0, StyleW);
1444 pFT_Done_Face(ft_face);
1447 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1448 TRACE("Original font is newer so skipping this one\n");
1449 HeapFree(GetProcessHeap(), 0, StyleW);
1450 pFT_Done_Face(ft_face);
1453 TRACE("Replacing original with this one\n");
1454 list_remove(&face->entry);
1455 HeapFree(GetProcessHeap(), 0, face->file);
1456 HeapFree(GetProcessHeap(), 0, face->StyleName);
1457 HeapFree(GetProcessHeap(), 0, face);
1462 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1463 face->cached_enum_data = NULL;
1464 face->StyleName = StyleW;
1465 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1468 face->file = strdupA(file);
1469 face->font_data_ptr = NULL;
1470 face->font_data_size = 0;
1475 face->font_data_ptr = font_data_ptr;
1476 face->font_data_size = font_data_size;
1478 face->face_index = face_index;
1480 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1481 face->ntmFlags |= NTM_ITALIC;
1482 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1483 face->ntmFlags |= NTM_BOLD;
1484 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1485 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1486 face->family = family;
1487 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1489 memset(&face->fs_links, 0, sizeof(face->fs_links));
1491 if(FT_IS_SCALABLE(ft_face)) {
1492 memset(&face->size, 0, sizeof(face->size));
1493 face->scalable = TRUE;
1495 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1496 size->height, size->width, size->size >> 6,
1497 size->x_ppem >> 6, size->y_ppem >> 6);
1498 face->size.height = size->height;
1499 face->size.width = size->width;
1500 face->size.size = size->size;
1501 face->size.x_ppem = size->x_ppem;
1502 face->size.y_ppem = size->y_ppem;
1503 face->size.internal_leading = internal_leading;
1504 face->scalable = FALSE;
1507 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1509 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1511 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1512 face->ntmFlags |= NTM_PS_OPENTYPE;
1515 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1516 face->fs.fsCsb[0], face->fs.fsCsb[1],
1517 face->fs.fsUsb[0], face->fs.fsUsb[1],
1518 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1521 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1522 for(i = 0; i < ft_face->num_charmaps; i++) {
1523 switch(ft_face->charmaps[i]->encoding) {
1524 case FT_ENCODING_UNICODE:
1525 case FT_ENCODING_APPLE_ROMAN:
1526 face->fs.fsCsb[0] |= FS_LATIN1;
1528 case FT_ENCODING_MS_SYMBOL:
1529 face->fs.fsCsb[0] |= FS_SYMBOL;
1537 AddFaceToFamily(face, family);
1539 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1541 num_faces = ft_face->num_faces;
1542 pFT_Done_Face(ft_face);
1543 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1544 debugstr_w(StyleW));
1545 } while(num_faces > ++face_index);
1549 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1551 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1554 static void DumpFontList(void)
1558 struct list *family_elem_ptr, *face_elem_ptr;
1560 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1561 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1562 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1563 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1564 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1565 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1567 TRACE(" %d", face->size.height);
1574 /***********************************************************
1575 * The replacement list is a way to map an entire font
1576 * family onto another family. For example adding
1578 * [HKCU\Software\Wine\Fonts\Replacements]
1579 * "Wingdings"="Winedings"
1581 * would enumerate the Winedings font both as Winedings and
1582 * Wingdings. However if a real Wingdings font is present the
1583 * replacement does not take place.
1586 static void LoadReplaceList(void)
1589 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1594 struct list *family_elem_ptr, *face_elem_ptr;
1597 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1598 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1600 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1601 &valuelen, &datalen, NULL, NULL);
1603 valuelen++; /* returned value doesn't include room for '\0' */
1604 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1605 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1609 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1610 &dlen) == ERROR_SUCCESS) {
1611 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1612 /* "NewName"="Oldname" */
1613 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1615 /* Find the old family and hence all of the font files
1617 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1618 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1619 if(!strcmpiW(family->FamilyName, data)) {
1620 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1621 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1622 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1623 debugstr_w(face->StyleName), familyA);
1624 /* Now add a new entry with the new family name */
1625 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1630 /* reset dlen and vlen */
1634 HeapFree(GetProcessHeap(), 0, data);
1635 HeapFree(GetProcessHeap(), 0, value);
1640 /*************************************************************
1643 static BOOL init_system_links(void)
1647 DWORD type, max_val, max_data, val_len, data_len, index;
1648 WCHAR *value, *data;
1649 WCHAR *entry, *next;
1650 SYSTEM_LINKS *font_link, *system_font_link;
1651 CHILD_FONT *child_font;
1652 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1653 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1659 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1661 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1662 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1663 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1664 val_len = max_val + 1;
1665 data_len = max_data;
1667 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1669 memset(&fs, 0, sizeof(fs));
1670 psub = get_font_subst(&font_subst_list, value, -1);
1671 /* Don't store fonts that are only substitutes for other fonts */
1674 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1677 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1678 font_link->font_name = strdupW(value);
1679 list_init(&font_link->links);
1680 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1683 CHILD_FONT *child_font;
1685 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1687 next = entry + strlenW(entry) + 1;
1689 face_name = strchrW(entry, ',');
1693 while(isspaceW(*face_name))
1696 psub = get_font_subst(&font_subst_list, face_name, -1);
1698 face_name = psub->to.name;
1700 face = find_face_from_filename(entry, face_name);
1703 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1707 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1708 child_font->face = face;
1709 child_font->font = NULL;
1710 fs.fsCsb[0] |= face->fs.fsCsb[0];
1711 fs.fsCsb[1] |= face->fs.fsCsb[1];
1712 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1713 list_add_tail(&font_link->links, &child_font->entry);
1715 family = find_family_from_name(font_link->font_name);
1718 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1720 face->fs_links = fs;
1723 list_add_tail(&system_links, &font_link->entry);
1725 val_len = max_val + 1;
1726 data_len = max_data;
1729 HeapFree(GetProcessHeap(), 0, value);
1730 HeapFree(GetProcessHeap(), 0, data);
1734 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1737 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1738 system_font_link->font_name = strdupW(System);
1739 list_init(&system_font_link->links);
1741 face = find_face_from_filename(tahoma_ttf, Tahoma);
1744 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1745 child_font->face = face;
1746 child_font->font = NULL;
1747 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1748 list_add_tail(&system_font_link->links, &child_font->entry);
1750 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1752 if(!strcmpiW(font_link->font_name, Tahoma))
1754 CHILD_FONT *font_link_entry;
1755 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1757 CHILD_FONT *new_child;
1758 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1759 new_child->face = font_link_entry->face;
1760 new_child->font = NULL;
1761 list_add_tail(&system_font_link->links, &new_child->entry);
1766 list_add_tail(&system_links, &system_font_link->entry);
1770 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1773 struct dirent *dent;
1774 char path[MAX_PATH];
1776 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1778 dir = opendir(dirname);
1780 WARN("Can't open directory %s\n", debugstr_a(dirname));
1783 while((dent = readdir(dir)) != NULL) {
1784 struct stat statbuf;
1786 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1789 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1791 sprintf(path, "%s/%s", dirname, dent->d_name);
1793 if(stat(path, &statbuf) == -1)
1795 WARN("Can't stat %s\n", debugstr_a(path));
1798 if(S_ISDIR(statbuf.st_mode))
1799 ReadFontDir(path, external_fonts);
1801 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1807 static void load_fontconfig_fonts(void)
1809 #ifdef SONAME_LIBFONTCONFIG
1810 void *fc_handle = NULL;
1819 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1821 TRACE("Wine cannot find the fontconfig library (%s).\n",
1822 SONAME_LIBFONTCONFIG);
1825 #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;}
1826 LOAD_FUNCPTR(FcConfigGetCurrent);
1827 LOAD_FUNCPTR(FcFontList);
1828 LOAD_FUNCPTR(FcFontSetDestroy);
1829 LOAD_FUNCPTR(FcInit);
1830 LOAD_FUNCPTR(FcObjectSetAdd);
1831 LOAD_FUNCPTR(FcObjectSetCreate);
1832 LOAD_FUNCPTR(FcObjectSetDestroy);
1833 LOAD_FUNCPTR(FcPatternCreate);
1834 LOAD_FUNCPTR(FcPatternDestroy);
1835 LOAD_FUNCPTR(FcPatternGetBool);
1836 LOAD_FUNCPTR(FcPatternGetString);
1839 if(!pFcInit()) return;
1841 config = pFcConfigGetCurrent();
1842 pat = pFcPatternCreate();
1843 os = pFcObjectSetCreate();
1844 pFcObjectSetAdd(os, FC_FILE);
1845 pFcObjectSetAdd(os, FC_SCALABLE);
1846 fontset = pFcFontList(config, pat, os);
1847 if(!fontset) return;
1848 for(i = 0; i < fontset->nfont; i++) {
1851 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1853 TRACE("fontconfig: %s\n", file);
1855 /* We're just interested in OT/TT fonts for now, so this hack just
1856 picks up the scalable fonts without extensions .pf[ab] to save time
1857 loading every other font */
1859 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1861 TRACE("not scalable\n");
1865 len = strlen( file );
1866 if(len < 4) continue;
1867 ext = &file[ len - 3 ];
1868 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1869 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1871 pFcFontSetDestroy(fontset);
1872 pFcObjectSetDestroy(os);
1873 pFcPatternDestroy(pat);
1879 static BOOL load_font_from_data_dir(LPCWSTR file)
1882 const char *data_dir = wine_get_data_dir();
1884 if (!data_dir) data_dir = wine_get_build_dir();
1891 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1893 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1895 strcpy(unix_name, data_dir);
1896 strcat(unix_name, "/fonts/");
1898 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1900 EnterCriticalSection( &freetype_cs );
1901 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1902 LeaveCriticalSection( &freetype_cs );
1903 HeapFree(GetProcessHeap(), 0, unix_name);
1908 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1910 static const WCHAR slashW[] = {'\\','\0'};
1912 WCHAR windowsdir[MAX_PATH];
1915 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1916 strcatW(windowsdir, fontsW);
1917 strcatW(windowsdir, slashW);
1918 strcatW(windowsdir, file);
1919 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1920 EnterCriticalSection( &freetype_cs );
1921 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1922 LeaveCriticalSection( &freetype_cs );
1923 HeapFree(GetProcessHeap(), 0, unixname);
1928 static void load_system_fonts(void)
1931 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1932 const WCHAR * const *value;
1934 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1937 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1938 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1939 strcatW(windowsdir, fontsW);
1940 for(value = SystemFontValues; *value; value++) {
1941 dlen = sizeof(data);
1942 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1946 sprintfW(pathW, fmtW, windowsdir, data);
1947 if((unixname = wine_get_unix_file_name(pathW))) {
1948 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1949 HeapFree(GetProcessHeap(), 0, unixname);
1952 load_font_from_data_dir(data);
1959 /*************************************************************
1961 * This adds registry entries for any externally loaded fonts
1962 * (fonts from fontconfig or FontDirs). It also deletes entries
1963 * of no longer existing fonts.
1966 static void update_reg_entries(void)
1968 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1973 struct list *family_elem_ptr, *face_elem_ptr;
1975 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1976 static const WCHAR spaceW[] = {' ', '\0'};
1979 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1980 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1981 ERR("Can't create Windows font reg key\n");
1985 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1986 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1987 ERR("Can't create Windows font reg key\n");
1991 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1992 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1993 ERR("Can't create external font reg key\n");
1997 /* enumerate the fonts and add external ones to the two keys */
1999 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2000 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2001 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2002 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2003 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2004 if(!face->external) continue;
2006 if (!(face->ntmFlags & NTM_REGULAR))
2007 len = len_fam + strlenW(face->StyleName) + 1;
2008 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2009 strcpyW(valueW, family->FamilyName);
2010 if(len != len_fam) {
2011 strcatW(valueW, spaceW);
2012 strcatW(valueW, face->StyleName);
2014 strcatW(valueW, TrueType);
2016 file = wine_get_dos_file_name(face->file);
2018 len = strlenW(file) + 1;
2021 if((path = strrchr(face->file, '/')) == NULL)
2025 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2027 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2028 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2030 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2031 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2032 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2034 HeapFree(GetProcessHeap(), 0, file);
2035 HeapFree(GetProcessHeap(), 0, valueW);
2039 if(external_key) RegCloseKey(external_key);
2040 if(win9x_key) RegCloseKey(win9x_key);
2041 if(winnt_key) RegCloseKey(winnt_key);
2045 static void delete_external_font_keys(void)
2047 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2048 DWORD dlen, vlen, datalen, valuelen, i, type;
2052 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2053 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2054 ERR("Can't create Windows font reg key\n");
2058 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2059 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2060 ERR("Can't create Windows font reg key\n");
2064 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2065 ERR("Can't create external font reg key\n");
2069 /* Delete all external fonts added last time */
2071 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2072 &valuelen, &datalen, NULL, NULL);
2073 valuelen++; /* returned value doesn't include room for '\0' */
2074 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2075 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2077 dlen = datalen * sizeof(WCHAR);
2080 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2081 &dlen) == ERROR_SUCCESS) {
2083 RegDeleteValueW(winnt_key, valueW);
2084 RegDeleteValueW(win9x_key, valueW);
2085 /* reset dlen and vlen */
2089 HeapFree(GetProcessHeap(), 0, data);
2090 HeapFree(GetProcessHeap(), 0, valueW);
2092 /* Delete the old external fonts key */
2093 RegCloseKey(external_key);
2094 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2097 if(win9x_key) RegCloseKey(win9x_key);
2098 if(winnt_key) RegCloseKey(winnt_key);
2101 /*************************************************************
2102 * WineEngAddFontResourceEx
2105 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2111 if (ft_handle) /* do it only if we have freetype up and running */
2116 FIXME("Ignoring flags %x\n", flags);
2118 if((unixname = wine_get_unix_file_name(file)))
2120 EnterCriticalSection( &freetype_cs );
2121 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2122 LeaveCriticalSection( &freetype_cs );
2123 HeapFree(GetProcessHeap(), 0, unixname);
2125 if (!ret && !strchrW(file, '\\')) {
2126 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2127 ret = load_font_from_winfonts_dir(file);
2129 /* Try in datadir/fonts (or builddir/fonts),
2130 * needed for Magic the Gathering Online
2132 ret = load_font_from_data_dir(file);
2139 /*************************************************************
2140 * WineEngAddFontMemResourceEx
2143 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2147 if (ft_handle) /* do it only if we have freetype up and running */
2149 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2151 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2152 memcpy(pFontCopy, pbFont, cbFont);
2154 EnterCriticalSection( &freetype_cs );
2155 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2156 LeaveCriticalSection( &freetype_cs );
2160 TRACE("AddFontToList failed\n");
2161 HeapFree(GetProcessHeap(), 0, pFontCopy);
2164 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2165 * For now return something unique but quite random
2167 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2168 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2175 /*************************************************************
2176 * WineEngRemoveFontResourceEx
2179 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2182 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2186 static const struct nls_update_font_list
2188 UINT ansi_cp, oem_cp;
2189 const char *oem, *fixed, *system;
2190 const char *courier, *serif, *small, *sserif;
2191 /* these are for font substitutes */
2192 const char *shelldlg, *tmsrmn;
2193 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2197 const char *from, *to;
2198 } arial_0, courier_new_0, times_new_roman_0;
2199 } nls_update_font_list[] =
2201 /* Latin 1 (United States) */
2202 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2203 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2204 "Tahoma","Times New Roman",
2205 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2208 /* Latin 1 (Multilingual) */
2209 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2210 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2211 "Tahoma","Times New Roman", /* FIXME unverified */
2212 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2215 /* Eastern Europe */
2216 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2217 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2218 "Tahoma","Times New Roman", /* FIXME unverified */
2219 "Fixedsys,238", "System,238",
2220 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2221 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2222 { "Arial CE,0", "Arial,238" },
2223 { "Courier New CE,0", "Courier New,238" },
2224 { "Times New Roman CE,0", "Times New Roman,238" }
2227 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2228 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2229 "Tahoma","Times New Roman", /* FIXME unverified */
2230 "Fixedsys,204", "System,204",
2231 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2232 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2233 { "Arial Cyr,0", "Arial,204" },
2234 { "Courier New Cyr,0", "Courier New,204" },
2235 { "Times New Roman Cyr,0", "Times New Roman,204" }
2238 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2239 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2240 "Tahoma","Times New Roman", /* FIXME unverified */
2241 "Fixedsys,161", "System,161",
2242 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2243 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2244 { "Arial Greek,0", "Arial,161" },
2245 { "Courier New Greek,0", "Courier New,161" },
2246 { "Times New Roman Greek,0", "Times New Roman,161" }
2249 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2250 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2251 "Tahoma","Times New Roman", /* FIXME unverified */
2252 "Fixedsys,162", "System,162",
2253 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2254 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2255 { "Arial Tur,0", "Arial,162" },
2256 { "Courier New Tur,0", "Courier New,162" },
2257 { "Times New Roman Tur,0", "Times New Roman,162" }
2260 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2261 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2262 "Tahoma","Times New Roman", /* FIXME unverified */
2263 "Fixedsys,177", "System,177",
2264 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2265 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2269 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2270 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2271 "Tahoma","Times New Roman", /* FIXME unverified */
2272 "Fixedsys,178", "System,178",
2273 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2274 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2278 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2279 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2280 "Tahoma","Times New Roman", /* FIXME unverified */
2281 "Fixedsys,186", "System,186",
2282 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2283 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2284 { "Arial Baltic,0", "Arial,186" },
2285 { "Courier New Baltic,0", "Courier New,186" },
2286 { "Times New Roman Baltic,0", "Times New Roman,186" }
2289 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2290 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2291 "Tahoma","Times New Roman", /* FIXME unverified */
2292 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2296 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2297 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2298 "Tahoma","Times New Roman", /* FIXME unverified */
2299 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2303 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2304 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2305 "MS UI Gothic","MS Serif",
2306 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2309 /* Chinese Simplified */
2310 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2311 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2312 "SimSun", "NSimSun",
2313 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2317 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2318 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2320 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2323 /* Chinese Traditional */
2324 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2325 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2326 "PMingLiU", "MingLiU",
2327 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2332 static const WCHAR *font_links_list[] =
2334 Lucida_Sans_Unicode,
2335 Microsoft_Sans_Serif,
2339 static const struct font_links_defaults_list
2341 /* Keyed off substitution for "MS Shell Dlg" */
2342 const WCHAR *shelldlg;
2343 /* Maximum of four substitutes, plus terminating NULL pointer */
2344 const WCHAR *substitutes[5];
2345 } font_links_defaults_list[] =
2347 /* Non East-Asian */
2348 { Tahoma, /* FIXME unverified ordering */
2349 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2351 /* Below lists are courtesy of
2352 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2356 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2358 /* Chinese Simplified */
2360 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2364 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2366 /* Chinese Traditional */
2368 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2372 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2374 return ( ansi_cp == 932 /* CP932 for Japanese */
2375 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2376 || ansi_cp == 949 /* CP949 for Korean */
2377 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2380 static inline HKEY create_fonts_NT_registry_key(void)
2384 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2385 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2389 static inline HKEY create_fonts_9x_registry_key(void)
2393 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2394 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2398 static inline HKEY create_config_fonts_registry_key(void)
2402 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2403 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2407 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2409 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2410 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2411 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2412 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2415 static void set_value_key(HKEY hkey, const char *name, const char *value)
2418 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2420 RegDeleteValueA(hkey, name);
2423 static void update_font_info(void)
2425 char buf[40], cpbuf[40];
2428 UINT i, ansi_cp = 0, oem_cp = 0;
2431 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2434 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2435 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2436 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2437 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2438 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2440 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2441 if (is_dbcs_ansi_cp(ansi_cp))
2442 use_default_fallback = TRUE;
2445 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2447 if (!strcmp( buf, cpbuf )) /* already set correctly */
2452 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2454 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2456 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2459 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2463 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2464 nls_update_font_list[i].oem_cp == oem_cp)
2466 hkey = create_config_fonts_registry_key();
2467 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2468 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2469 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2472 hkey = create_fonts_NT_registry_key();
2473 add_font_list(hkey, &nls_update_font_list[i]);
2476 hkey = create_fonts_9x_registry_key();
2477 add_font_list(hkey, &nls_update_font_list[i]);
2480 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2482 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2483 strlen(nls_update_font_list[i].shelldlg)+1);
2484 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2485 strlen(nls_update_font_list[i].tmsrmn)+1);
2487 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2488 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2489 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2490 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2491 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2492 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2493 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2494 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2496 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2497 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2498 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2506 /* Delete the FontSubstitutes from other locales */
2507 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2509 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2510 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2511 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2517 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2519 /* Clear out system links */
2520 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2523 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2533 WCHAR buff[MAX_PATH];
2537 static const WCHAR comma[] = {',',0};
2539 RegDeleteValueW(hkey, name);
2544 for (i = 0; values[i] != NULL; i++)
2547 if (!strcmpiW(name,value))
2549 psub = get_font_subst(&font_subst_list, value, -1);
2551 value = psub->to.name;
2552 family = find_family_from_name(value);
2556 /* Use first extant filename for this Family */
2557 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2561 file = strrchr(face->file, '/');
2570 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2571 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2572 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2573 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2574 if (sizeof(buff)-(data-buff) < entryLen + 1)
2576 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2577 HeapFree(GetProcessHeap(), 0, fileW);
2580 strcpyW(data, fileW);
2581 strcatW(data, comma);
2582 strcatW(data, value);
2584 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2585 HeapFree(GetProcessHeap(), 0, fileW);
2591 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2593 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2595 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2598 static void update_system_links(void)
2606 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2608 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2610 if (disposition == REG_OPENED_EXISTING_KEY)
2612 TRACE("SystemLink key already exists, doing nothing\n");
2617 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2619 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2624 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2626 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2628 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2629 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2631 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2632 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2635 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2637 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2642 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2644 WARN("failed to create SystemLink key\n");
2648 static BOOL init_freetype(void)
2650 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2653 "Wine cannot find the FreeType font library. To enable Wine to\n"
2654 "use TrueType fonts please install a version of FreeType greater than\n"
2655 "or equal to 2.0.5.\n"
2656 "http://www.freetype.org\n");
2660 #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;}
2662 LOAD_FUNCPTR(FT_Vector_Unit)
2663 LOAD_FUNCPTR(FT_Done_Face)
2664 LOAD_FUNCPTR(FT_Get_Char_Index)
2665 LOAD_FUNCPTR(FT_Get_Module)
2666 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2667 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2668 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2669 LOAD_FUNCPTR(FT_Init_FreeType)
2670 LOAD_FUNCPTR(FT_Load_Glyph)
2671 LOAD_FUNCPTR(FT_Matrix_Multiply)
2672 #ifndef FT_MULFIX_INLINED
2673 LOAD_FUNCPTR(FT_MulFix)
2675 LOAD_FUNCPTR(FT_New_Face)
2676 LOAD_FUNCPTR(FT_New_Memory_Face)
2677 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2678 LOAD_FUNCPTR(FT_Outline_Transform)
2679 LOAD_FUNCPTR(FT_Outline_Translate)
2680 LOAD_FUNCPTR(FT_Select_Charmap)
2681 LOAD_FUNCPTR(FT_Set_Charmap)
2682 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2683 LOAD_FUNCPTR(FT_Vector_Transform)
2684 LOAD_FUNCPTR(FT_Render_Glyph)
2687 /* Don't warn if these ones are missing */
2688 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2689 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2690 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2691 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2692 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2693 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2694 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2696 #ifdef HAVE_FREETYPE_FTWINFNT_H
2697 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2699 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2700 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2701 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2702 <= 2.0.3 has FT_Sqrt64 */
2706 if(pFT_Init_FreeType(&library) != 0) {
2707 ERR("Can't init FreeType library\n");
2708 wine_dlclose(ft_handle, NULL, 0);
2712 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2713 if (pFT_Library_Version)
2714 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2716 if (FT_Version.major<=0)
2722 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2723 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2724 ((FT_Version.minor << 8) & 0x00ff00) |
2725 ((FT_Version.patch ) & 0x0000ff);
2731 "Wine cannot find certain functions that it needs inside the FreeType\n"
2732 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2733 "FreeType to at least version 2.0.5.\n"
2734 "http://www.freetype.org\n");
2735 wine_dlclose(ft_handle, NULL, 0);
2740 /*************************************************************
2743 * Initialize FreeType library and create a list of available faces
2745 BOOL WineEngInit(void)
2747 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2748 static const WCHAR pathW[] = {'P','a','t','h',0};
2750 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2751 WCHAR windowsdir[MAX_PATH];
2754 const char *data_dir;
2758 /* update locale dependent font info in registry */
2761 if(!init_freetype()) return FALSE;
2763 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2764 ERR("Failed to create font mutex\n");
2767 WaitForSingleObject(font_mutex, INFINITE);
2769 delete_external_font_keys();
2771 /* load the system bitmap fonts */
2772 load_system_fonts();
2774 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2775 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2776 strcatW(windowsdir, fontsW);
2777 if((unixname = wine_get_unix_file_name(windowsdir)))
2779 ReadFontDir(unixname, FALSE);
2780 HeapFree(GetProcessHeap(), 0, unixname);
2783 /* load the system truetype fonts */
2784 data_dir = wine_get_data_dir();
2785 if (!data_dir) data_dir = wine_get_build_dir();
2786 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2787 strcpy(unixname, data_dir);
2788 strcat(unixname, "/fonts/");
2789 ReadFontDir(unixname, TRUE);
2790 HeapFree(GetProcessHeap(), 0, unixname);
2793 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2794 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2795 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2797 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2798 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2799 &hkey) == ERROR_SUCCESS) {
2800 LPWSTR data, valueW;
2801 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2802 &valuelen, &datalen, NULL, NULL);
2804 valuelen++; /* returned value doesn't include room for '\0' */
2805 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2806 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2809 dlen = datalen * sizeof(WCHAR);
2811 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2812 &dlen) == ERROR_SUCCESS) {
2813 if(data[0] && (data[1] == ':'))
2815 if((unixname = wine_get_unix_file_name(data)))
2817 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2818 HeapFree(GetProcessHeap(), 0, unixname);
2821 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2823 WCHAR pathW[MAX_PATH];
2824 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2827 sprintfW(pathW, fmtW, windowsdir, data);
2828 if((unixname = wine_get_unix_file_name(pathW)))
2830 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2831 HeapFree(GetProcessHeap(), 0, unixname);
2834 load_font_from_data_dir(data);
2836 /* reset dlen and vlen */
2841 HeapFree(GetProcessHeap(), 0, data);
2842 HeapFree(GetProcessHeap(), 0, valueW);
2846 load_fontconfig_fonts();
2848 /* then look in any directories that we've specified in the config file */
2849 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2850 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2856 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2858 len += sizeof(WCHAR);
2859 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2860 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2862 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2863 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2864 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2865 TRACE( "got font path %s\n", debugstr_a(valueA) );
2869 LPSTR next = strchr( ptr, ':' );
2870 if (next) *next++ = 0;
2871 ReadFontDir( ptr, TRUE );
2874 HeapFree( GetProcessHeap(), 0, valueA );
2876 HeapFree( GetProcessHeap(), 0, valueW );
2885 update_reg_entries();
2887 update_system_links();
2888 init_system_links();
2890 ReleaseMutex(font_mutex);
2895 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2898 TT_HoriHeader *pHori;
2902 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2903 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2905 if(height == 0) height = 16;
2907 /* Calc. height of EM square:
2909 * For +ve lfHeight we have
2910 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2911 * Re-arranging gives:
2912 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2914 * For -ve lfHeight we have
2916 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2917 * with il = winAscent + winDescent - units_per_em]
2922 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2923 ppem = MulDiv(ft_face->units_per_EM, height,
2924 pHori->Ascender - pHori->Descender);
2926 ppem = MulDiv(ft_face->units_per_EM, height,
2927 pOS2->usWinAscent + pOS2->usWinDescent);
2935 static struct font_mapping *map_font_file( const char *name )
2937 struct font_mapping *mapping;
2941 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2942 if (fstat( fd, &st ) == -1) goto error;
2944 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2946 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2948 mapping->refcount++;
2953 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2956 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2959 if (mapping->data == MAP_FAILED)
2961 HeapFree( GetProcessHeap(), 0, mapping );
2964 mapping->refcount = 1;
2965 mapping->dev = st.st_dev;
2966 mapping->ino = st.st_ino;
2967 mapping->size = st.st_size;
2968 list_add_tail( &mappings_list, &mapping->entry );
2976 static void unmap_font_file( struct font_mapping *mapping )
2978 if (!--mapping->refcount)
2980 list_remove( &mapping->entry );
2981 munmap( mapping->data, mapping->size );
2982 HeapFree( GetProcessHeap(), 0, mapping );
2986 static LONG load_VDMX(GdiFont*, LONG);
2988 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2995 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2999 if (!(font->mapping = map_font_file( face->file )))
3001 WARN("failed to map %s\n", debugstr_a(face->file));
3004 data_ptr = font->mapping->data;
3005 data_size = font->mapping->size;
3009 data_ptr = face->font_data_ptr;
3010 data_size = face->font_data_size;
3013 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3015 ERR("FT_New_Face rets %d\n", err);
3019 /* set it here, as load_VDMX needs it */
3020 font->ft_face = ft_face;
3022 if(FT_IS_SCALABLE(ft_face)) {
3023 /* load the VDMX table if we have one */
3024 font->ppem = load_VDMX(font, height);
3026 font->ppem = calc_ppem_for_height(ft_face, height);
3027 TRACE("height %d => ppem %d\n", height, font->ppem);
3029 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3030 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3032 font->ppem = height;
3033 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3034 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3040 static int get_nearest_charset(Face *face, int *cp)
3042 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3043 a single face with the requested charset. The idea is to check if
3044 the selected font supports the current ANSI codepage, if it does
3045 return the corresponding charset, else return the first charset */
3048 int acp = GetACP(), i;
3052 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3053 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3054 return csi.ciCharset;
3056 for(i = 0; i < 32; i++) {
3058 if(face->fs.fsCsb[0] & fs0) {
3059 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3061 return csi.ciCharset;
3064 FIXME("TCI failing on %x\n", fs0);
3068 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3069 face->fs.fsCsb[0], face->file);
3071 return DEFAULT_CHARSET;
3074 static GdiFont *alloc_font(void)
3076 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3078 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3079 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3081 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3082 ret->total_kern_pairs = (DWORD)-1;
3083 ret->kern_pairs = NULL;
3084 list_init(&ret->hfontlist);
3085 list_init(&ret->child_fonts);
3089 static void free_font(GdiFont *font)
3091 struct list *cursor, *cursor2;
3094 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3096 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3097 list_remove(cursor);
3099 free_font(child->font);
3100 HeapFree(GetProcessHeap(), 0, child);
3103 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3105 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3106 DeleteObject(hfontlist->hfont);
3107 list_remove(&hfontlist->entry);
3108 HeapFree(GetProcessHeap(), 0, hfontlist);
3111 if (font->ft_face) pFT_Done_Face(font->ft_face);
3112 if (font->mapping) unmap_font_file( font->mapping );
3113 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3114 HeapFree(GetProcessHeap(), 0, font->potm);
3115 HeapFree(GetProcessHeap(), 0, font->name);
3116 for (i = 0; i < font->gmsize; i++)
3117 HeapFree(GetProcessHeap(),0,font->gm[i]);
3118 HeapFree(GetProcessHeap(), 0, font->gm);
3119 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3120 HeapFree(GetProcessHeap(), 0, font);
3124 /*************************************************************
3127 * load the vdmx entry for the specified height
3130 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3131 ( ( (FT_ULong)_x4 << 24 ) | \
3132 ( (FT_ULong)_x3 << 16 ) | \
3133 ( (FT_ULong)_x2 << 8 ) | \
3136 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3151 static LONG load_VDMX(GdiFont *font, LONG height)
3155 BYTE devXRatio, devYRatio;
3156 USHORT numRecs, numRatios;
3157 DWORD result, offset = -1;
3161 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3163 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3166 /* FIXME: need the real device aspect ratio */
3170 numRecs = GET_BE_WORD(hdr[1]);
3171 numRatios = GET_BE_WORD(hdr[2]);
3173 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3174 for(i = 0; i < numRatios; i++) {
3177 offset = (3 * 2) + (i * sizeof(Ratios));
3178 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3181 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3183 if((ratio.xRatio == 0 &&
3184 ratio.yStartRatio == 0 &&
3185 ratio.yEndRatio == 0) ||
3186 (devXRatio == ratio.xRatio &&
3187 devYRatio >= ratio.yStartRatio &&
3188 devYRatio <= ratio.yEndRatio))
3190 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3191 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3192 offset = GET_BE_WORD(tmp);
3198 FIXME("No suitable ratio found\n");
3202 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3204 BYTE startsz, endsz;
3207 recs = GET_BE_WORD(group.recs);
3208 startsz = group.startsz;
3209 endsz = group.endsz;
3211 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3213 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3214 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3215 if(result == GDI_ERROR) {
3216 FIXME("Failed to retrieve vTable\n");
3221 for(i = 0; i < recs; i++) {
3222 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3223 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3224 ppem = GET_BE_WORD(vTable[i * 3]);
3226 if(yMax + -yMin == height) {
3229 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3232 if(yMax + -yMin > height) {
3235 goto end; /* failed */
3237 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3238 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3239 ppem = GET_BE_WORD(vTable[i * 3]);
3240 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3246 TRACE("ppem not found for height %d\n", height);
3250 HeapFree(GetProcessHeap(), 0, vTable);
3256 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3258 if(font->font_desc.hash != fd->hash) return TRUE;
3259 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3260 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3261 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3262 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3265 static void calc_hash(FONT_DESC *pfd)
3267 DWORD hash = 0, *ptr, two_chars;
3271 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3273 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3275 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3277 pwc = (WCHAR *)&two_chars;
3279 *pwc = toupperW(*pwc);
3281 *pwc = toupperW(*pwc);
3285 hash ^= !pfd->can_use_bitmap;
3290 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3295 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3299 fd.can_use_bitmap = can_use_bitmap;
3302 /* try the child list */
3303 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3304 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3305 if(!fontcmp(ret, &fd)) {
3306 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3307 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3308 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3309 if(hflist->hfont == hfont)
3315 /* try the in-use list */
3316 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3317 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3318 if(!fontcmp(ret, &fd)) {
3319 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3320 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3321 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3322 if(hflist->hfont == hfont)
3325 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3326 hflist->hfont = hfont;
3327 list_add_head(&ret->hfontlist, &hflist->entry);
3332 /* then the unused list */
3333 font_elem_ptr = list_head(&unused_gdi_font_list);
3334 while(font_elem_ptr) {
3335 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3336 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3337 if(!fontcmp(ret, &fd)) {
3338 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3339 assert(list_empty(&ret->hfontlist));
3340 TRACE("Found %p in unused list\n", ret);
3341 list_remove(&ret->entry);
3342 list_add_head(&gdi_font_list, &ret->entry);
3343 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3344 hflist->hfont = hfont;
3345 list_add_head(&ret->hfontlist, &hflist->entry);
3352 static void add_to_cache(GdiFont *font)
3354 static DWORD cache_num = 1;
3356 font->cache_num = cache_num++;
3357 list_add_head(&gdi_font_list, &font->entry);
3360 /*************************************************************
3361 * create_child_font_list
3363 static BOOL create_child_font_list(GdiFont *font)
3366 SYSTEM_LINKS *font_link;
3367 CHILD_FONT *font_link_entry, *new_child;
3371 psub = get_font_subst(&font_subst_list, font->name, -1);
3372 font_name = psub ? psub->to.name : font->name;
3373 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3375 if(!strcmpiW(font_link->font_name, font_name))
3377 TRACE("found entry in system list\n");
3378 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3380 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3381 new_child->face = font_link_entry->face;
3382 new_child->font = NULL;
3383 list_add_tail(&font->child_fonts, &new_child->entry);
3384 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3391 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3392 * Sans Serif. This is how asian windows get default fallbacks for fonts
3394 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3395 font->charset != OEM_CHARSET &&
3396 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3397 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3399 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3401 TRACE("found entry in default fallback list\n");
3402 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3404 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3405 new_child->face = font_link_entry->face;
3406 new_child->font = NULL;
3407 list_add_tail(&font->child_fonts, &new_child->entry);
3408 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3418 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3420 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3422 if (pFT_Set_Charmap)
3425 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3427 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3429 for (i = 0; i < ft_face->num_charmaps; i++)
3431 if (ft_face->charmaps[i]->encoding == encoding)
3433 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3434 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3436 switch (ft_face->charmaps[i]->platform_id)
3439 cmap_def = ft_face->charmaps[i];
3441 case 0: /* Apple Unicode */
3442 cmap0 = ft_face->charmaps[i];
3444 case 1: /* Macintosh */
3445 cmap1 = ft_face->charmaps[i];
3448 cmap2 = ft_face->charmaps[i];
3450 case 3: /* Microsoft */
3451 cmap3 = ft_face->charmaps[i];
3456 if (cmap3) /* prefer Microsoft cmap table */
3457 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3459 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3461 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3463 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3465 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3467 return ft_err == FT_Err_Ok;
3470 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3473 /*************************************************************
3474 * WineEngCreateFontInstance
3477 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3480 Face *face, *best, *best_bitmap;
3481 Family *family, *last_resort_family;
3482 struct list *family_elem_ptr, *face_elem_ptr;
3483 INT height, width = 0;
3484 unsigned int score = 0, new_score;
3485 signed int diff = 0, newdiff;
3486 BOOL bd, it, can_use_bitmap;
3491 FontSubst *psub = NULL;
3493 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3494 lf.lfWidth = abs(lf.lfWidth);
3496 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3498 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3499 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3500 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3503 if(dc->GraphicsMode == GM_ADVANCED)
3504 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3507 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3508 font scaling abilities. */
3509 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3510 dcmat.eM21 = dcmat.eM12 = 0;
3513 /* Try to avoid not necessary glyph transformations */
3514 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3516 lf.lfHeight *= fabs(dcmat.eM11);
3517 lf.lfWidth *= fabs(dcmat.eM11);
3518 dcmat.eM11 = dcmat.eM22 = 1.0;
3521 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3522 dcmat.eM21, dcmat.eM22);
3525 EnterCriticalSection( &freetype_cs );
3527 /* check the cache first */
3528 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3529 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3530 LeaveCriticalSection( &freetype_cs );
3534 TRACE("not in cache\n");
3535 if(list_empty(&font_list)) /* No fonts installed */
3537 TRACE("No fonts installed\n");
3538 LeaveCriticalSection( &freetype_cs );
3544 ret->font_desc.matrix = dcmat;
3545 ret->font_desc.lf = lf;
3546 ret->font_desc.can_use_bitmap = can_use_bitmap;
3547 calc_hash(&ret->font_desc);
3548 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3549 hflist->hfont = hfont;
3550 list_add_head(&ret->hfontlist, &hflist->entry);
3552 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3553 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3554 original value lfCharSet. Note this is a special case for
3555 Symbol and doesn't happen at least for "Wingdings*" */
3557 if(!strcmpiW(lf.lfFaceName, SymbolW))
3558 lf.lfCharSet = SYMBOL_CHARSET;
3560 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3561 switch(lf.lfCharSet) {
3562 case DEFAULT_CHARSET:
3563 csi.fs.fsCsb[0] = 0;
3566 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3567 csi.fs.fsCsb[0] = 0;
3573 if(lf.lfFaceName[0] != '\0') {
3574 SYSTEM_LINKS *font_link;
3575 CHILD_FONT *font_link_entry;
3576 LPWSTR FaceName = lf.lfFaceName;
3579 * Check for a leading '@' this signals that the font is being
3580 * requested in tategaki mode (vertical writing substitution) but
3581 * does not affect the fontface that is to be selected.
3583 if (lf.lfFaceName[0]=='@')
3584 FaceName = &lf.lfFaceName[1];
3586 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3589 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3590 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3591 if (psub->to.charset != -1)
3592 lf.lfCharSet = psub->to.charset;
3595 /* We want a match on name and charset or just name if
3596 charset was DEFAULT_CHARSET. If the latter then
3597 we fixup the returned charset later in get_nearest_charset
3598 where we'll either use the charset of the current ansi codepage
3599 or if that's unavailable the first charset that the font supports.
3601 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3602 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3603 if (!strcmpiW(family->FamilyName, FaceName) ||
3604 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3606 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3607 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3608 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3609 if(face->scalable || can_use_bitmap)
3615 /* Search by full face name. */
3616 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3617 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3618 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3619 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3620 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3621 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3623 if(face->scalable || can_use_bitmap)
3630 * Try check the SystemLink list first for a replacement font.
3631 * We may find good replacements there.
3633 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3635 if(!strcmpiW(font_link->font_name, FaceName) ||
3636 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3638 TRACE("found entry in system list\n");
3639 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3641 face = font_link_entry->face;
3642 family = face->family;
3643 if(csi.fs.fsCsb[0] &
3644 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3646 if(face->scalable || can_use_bitmap)
3654 psub = NULL; /* substitution is no more relevant */
3656 /* If requested charset was DEFAULT_CHARSET then try using charset
3657 corresponding to the current ansi codepage */
3658 if (!csi.fs.fsCsb[0])
3661 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3662 FIXME("TCI failed on codepage %d\n", acp);
3663 csi.fs.fsCsb[0] = 0;
3665 lf.lfCharSet = csi.ciCharset;
3668 /* Face families are in the top 4 bits of lfPitchAndFamily,
3669 so mask with 0xF0 before testing */
3671 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3672 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3673 strcpyW(lf.lfFaceName, defFixed);
3674 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3675 strcpyW(lf.lfFaceName, defSerif);
3676 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3677 strcpyW(lf.lfFaceName, defSans);
3679 strcpyW(lf.lfFaceName, defSans);
3680 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3681 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3682 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3683 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3684 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3685 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3686 if(face->scalable || can_use_bitmap)
3692 last_resort_family = NULL;
3693 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3694 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3695 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3696 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3697 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3700 if(can_use_bitmap && !last_resort_family)
3701 last_resort_family = family;
3706 if(last_resort_family) {
3707 family = last_resort_family;
3708 csi.fs.fsCsb[0] = 0;
3712 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3713 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3714 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3715 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3716 if(face->scalable) {
3717 csi.fs.fsCsb[0] = 0;
3718 WARN("just using first face for now\n");
3721 if(can_use_bitmap && !last_resort_family)
3722 last_resort_family = family;
3725 if(!last_resort_family) {
3726 FIXME("can't find a single appropriate font - bailing\n");
3728 LeaveCriticalSection( &freetype_cs );
3732 WARN("could only find a bitmap font - this will probably look awful!\n");
3733 family = last_resort_family;
3734 csi.fs.fsCsb[0] = 0;
3737 it = lf.lfItalic ? 1 : 0;
3738 bd = lf.lfWeight > 550 ? 1 : 0;
3740 height = lf.lfHeight;
3742 face = best = best_bitmap = NULL;
3743 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3745 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3749 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3750 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3751 new_score = (italic ^ it) + (bold ^ bd);
3752 if(!best || new_score <= score)
3754 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3755 italic, bold, it, bd);
3758 if(best->scalable && score == 0) break;
3762 newdiff = height - (signed int)(best->size.height);
3764 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3765 if(!best_bitmap || new_score < score ||
3766 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3768 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3771 if(score == 0 && diff == 0) break;
3778 face = best->scalable ? best : best_bitmap;
3779 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3780 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3783 height = lf.lfHeight;
3787 if(csi.fs.fsCsb[0]) {
3788 ret->charset = lf.lfCharSet;
3789 ret->codepage = csi.ciACP;
3792 ret->charset = get_nearest_charset(face, &ret->codepage);
3794 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3795 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3797 ret->aveWidth = height ? lf.lfWidth : 0;
3799 if(!face->scalable) {
3800 /* Windows uses integer scaling factors for bitmap fonts */
3801 INT scale, scaled_height;
3802 GdiFont *cachedfont;
3804 /* FIXME: rotation of bitmap fonts is ignored */
3805 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3807 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3808 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3809 dcmat.eM11 = dcmat.eM22 = 1.0;
3810 /* As we changed the matrix, we need to search the cache for the font again,
3811 * otherwise we might explode the cache. */
3812 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3813 TRACE("Found cached font after non-scalable matrix rescale!\n");
3815 LeaveCriticalSection( &freetype_cs );
3818 calc_hash(&ret->font_desc);
3820 if (height != 0) height = diff;
3821 height += face->size.height;
3823 scale = (height + face->size.height - 1) / face->size.height;
3824 scaled_height = scale * face->size.height;
3825 /* Only jump to the next height if the difference <= 25% original height */
3826 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3827 /* The jump between unscaled and doubled is delayed by 1 */
3828 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3829 ret->scale_y = scale;
3831 width = face->size.x_ppem >> 6;
3832 height = face->size.y_ppem >> 6;
3836 TRACE("font scale y: %f\n", ret->scale_y);
3838 ret->ft_face = OpenFontFace(ret, face, width, height);
3843 LeaveCriticalSection( &freetype_cs );
3847 ret->ntmFlags = face->ntmFlags;
3849 if (ret->charset == SYMBOL_CHARSET &&
3850 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3853 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3857 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3860 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3861 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3862 ret->underline = lf.lfUnderline ? 0xff : 0;
3863 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3864 create_child_font_list(ret);
3866 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3868 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3869 if (length != GDI_ERROR)
3871 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3872 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3873 TRACE("Loaded GSUB table of %i bytes\n",length);
3877 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3880 LeaveCriticalSection( &freetype_cs );
3884 static void dump_gdi_font_list(void)
3887 struct list *elem_ptr;
3889 TRACE("---------- gdiFont Cache ----------\n");
3890 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3891 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3892 TRACE("gdiFont=%p %s %d\n",
3893 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3896 TRACE("---------- Unused gdiFont Cache ----------\n");
3897 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3898 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3899 TRACE("gdiFont=%p %s %d\n",
3900 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3903 TRACE("---------- Child gdiFont Cache ----------\n");
3904 LIST_FOR_EACH(elem_ptr, &child_font_list) {
3905 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3906 TRACE("gdiFont=%p %s %d\n",
3907 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3911 /*************************************************************
3912 * WineEngDestroyFontInstance
3914 * free the gdiFont associated with this handle
3917 BOOL WineEngDestroyFontInstance(HFONT handle)
3922 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3926 EnterCriticalSection( &freetype_cs );
3928 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3930 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3931 while(hfontlist_elem_ptr) {
3932 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3933 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3934 if(hflist->hfont == handle) {
3935 TRACE("removing child font %p from child list\n", gdiFont);
3936 list_remove(&gdiFont->entry);
3937 LeaveCriticalSection( &freetype_cs );
3943 TRACE("destroying hfont=%p\n", handle);
3945 dump_gdi_font_list();
3947 font_elem_ptr = list_head(&gdi_font_list);
3948 while(font_elem_ptr) {
3949 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3950 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3952 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3953 while(hfontlist_elem_ptr) {
3954 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3955 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3956 if(hflist->hfont == handle) {
3957 list_remove(&hflist->entry);
3958 HeapFree(GetProcessHeap(), 0, hflist);
3962 if(list_empty(&gdiFont->hfontlist)) {
3963 TRACE("Moving to Unused list\n");
3964 list_remove(&gdiFont->entry);
3965 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3970 font_elem_ptr = list_head(&unused_gdi_font_list);
3971 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3972 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3973 while(font_elem_ptr) {
3974 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3975 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3976 TRACE("freeing %p\n", gdiFont);
3977 list_remove(&gdiFont->entry);
3980 LeaveCriticalSection( &freetype_cs );
3984 /***************************************************
3985 * create_enum_charset_list
3987 * This function creates charset enumeration list because in DEFAULT_CHARSET
3988 * case, the ANSI codepage's charset takes precedence over other charsets.
3989 * This function works as a filter other than DEFAULT_CHARSET case.
3991 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
3996 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
3997 csi.fs.fsCsb[0] != 0) {
3998 list->element[n].mask = csi.fs.fsCsb[0];
3999 list->element[n].charset = csi.ciCharset;
4000 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4003 else { /* charset is DEFAULT_CHARSET or invalid. */
4006 /* Set the current codepage's charset as the first element. */
4008 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4009 csi.fs.fsCsb[0] != 0) {
4010 list->element[n].mask = csi.fs.fsCsb[0];
4011 list->element[n].charset = csi.ciCharset;
4012 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4016 /* Fill out left elements. */
4017 for (i = 0; i < 32; i++) {
4019 fs.fsCsb[0] = 1L << i;
4021 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4022 continue; /* skip, already added. */
4023 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4024 continue; /* skip, this is an invalid fsCsb bit. */
4026 list->element[n].mask = fs.fsCsb[0];
4027 list->element[n].charset = csi.ciCharset;
4028 list->element[n].name = ElfScriptsW[i];
4037 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4038 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4043 if (face->cached_enum_data)
4046 *pelf = face->cached_enum_data->elf;
4047 *pntm = face->cached_enum_data->ntm;
4048 *ptype = face->cached_enum_data->type;
4052 font = alloc_font();
4054 if(face->scalable) {
4055 height = -2048; /* 2048 is the most common em size */
4058 height = face->size.y_ppem >> 6;
4059 width = face->size.x_ppem >> 6;
4061 font->scale_y = 1.0;
4063 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4069 font->name = strdupW(face->family->FamilyName);
4070 font->ntmFlags = face->ntmFlags;
4072 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4074 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4076 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4078 lstrcpynW(pelf->elfLogFont.lfFaceName,
4079 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4081 lstrcpynW(pelf->elfFullName,
4082 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4084 lstrcpynW(pelf->elfStyle,
4085 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4090 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4092 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4094 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4095 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4096 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4099 pntm->ntmTm.ntmFlags = face->ntmFlags;
4100 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4101 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4102 pntm->ntmFontSig = face->fs;
4104 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4106 pelf->elfLogFont.lfEscapement = 0;
4107 pelf->elfLogFont.lfOrientation = 0;
4108 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4109 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4110 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4111 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4112 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4113 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4114 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4115 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4116 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4117 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4118 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4121 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4122 *ptype |= TRUETYPE_FONTTYPE;
4123 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4124 *ptype |= DEVICE_FONTTYPE;
4125 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4126 *ptype |= RASTER_FONTTYPE;
4128 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4129 if (face->cached_enum_data)
4131 face->cached_enum_data->elf = *pelf;
4132 face->cached_enum_data->ntm = *pntm;
4133 face->cached_enum_data->type = *ptype;
4139 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4141 struct list *face_elem_ptr;
4143 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4145 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4147 static const WCHAR spaceW[] = { ' ',0 };
4148 WCHAR full_family_name[LF_FULLFACESIZE];
4149 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4151 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4153 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4154 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4158 strcpyW(full_family_name, family->FamilyName);
4159 strcatW(full_family_name, spaceW);
4160 strcatW(full_family_name, face->StyleName);
4161 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4167 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4169 static const WCHAR spaceW[] = { ' ',0 };
4170 WCHAR full_family_name[LF_FULLFACESIZE];
4172 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4174 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4176 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4177 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4181 strcpyW(full_family_name, face->family->FamilyName);
4182 strcatW(full_family_name, spaceW);
4183 strcatW(full_family_name, face->StyleName);
4184 return !strcmpiW(lf->lfFaceName, full_family_name);
4187 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4188 FONTENUMPROCW proc, LPARAM lparam)
4191 NEWTEXTMETRICEXW ntm;
4195 GetEnumStructs(face, &elf, &ntm, &type);
4196 for(i = 0; i < list->total; i++) {
4197 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4198 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4199 strcpyW(elf.elfScript, OEM_DOSW);
4200 i = 32; /* break out of loop */
4201 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4204 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4205 if(list->element[i].name)
4206 strcpyW(elf.elfScript, list->element[i].name);
4208 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4210 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4211 debugstr_w(elf.elfLogFont.lfFaceName),
4212 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4213 list->element[i].charset, type, debugstr_w(elf.elfScript),
4214 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4215 ntm.ntmTm.ntmFlags);
4216 /* release section before callback (FIXME) */
4217 LeaveCriticalSection( &freetype_cs );
4218 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4219 EnterCriticalSection( &freetype_cs );
4224 /*************************************************************
4228 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4232 struct list *family_elem_ptr, *face_elem_ptr;
4234 struct enum_charset_list enum_charsets;
4238 lf.lfCharSet = DEFAULT_CHARSET;
4239 lf.lfPitchAndFamily = 0;
4240 lf.lfFaceName[0] = 0;
4244 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4246 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4249 EnterCriticalSection( &freetype_cs );
4250 if(plf->lfFaceName[0]) {
4252 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4255 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4256 debugstr_w(psub->to.name));
4258 strcpyW(lf.lfFaceName, psub->to.name);
4262 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4263 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4264 if(family_matches(family, plf)) {
4265 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4266 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4267 if (!face_matches(face, plf)) continue;
4268 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4273 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4274 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4275 face_elem_ptr = list_head(&family->faces);
4276 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4277 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4280 LeaveCriticalSection( &freetype_cs );
4284 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4286 pt->x.value = vec->x >> 6;
4287 pt->x.fract = (vec->x & 0x3f) << 10;
4288 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4289 pt->y.value = vec->y >> 6;
4290 pt->y.fract = (vec->y & 0x3f) << 10;
4291 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4295 /***************************************************
4296 * According to the MSDN documentation on WideCharToMultiByte,
4297 * certain codepages cannot set the default_used parameter.
4298 * This returns TRUE if the codepage can set that parameter, false else
4299 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4301 static BOOL codepage_sets_default_used(UINT codepage)
4315 * GSUB Table handling functions
4318 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4320 const GSUB_CoverageFormat1* cf1;
4324 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4326 int count = GET_BE_WORD(cf1->GlyphCount);
4328 TRACE("Coverage Format 1, %i glyphs\n",count);
4329 for (i = 0; i < count; i++)
4330 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4334 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4336 const GSUB_CoverageFormat2* cf2;
4339 cf2 = (const GSUB_CoverageFormat2*)cf1;
4341 count = GET_BE_WORD(cf2->RangeCount);
4342 TRACE("Coverage Format 2, %i ranges\n",count);
4343 for (i = 0; i < count; i++)
4345 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4347 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4348 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4350 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4351 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4357 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4362 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4364 const GSUB_ScriptList *script;
4365 const GSUB_Script *deflt = NULL;
4367 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4369 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4370 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4372 const GSUB_Script *scr;
4375 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4376 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4378 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4380 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4386 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4390 const GSUB_LangSys *Lang;
4392 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4394 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4396 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4397 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4399 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4402 offset = GET_BE_WORD(script->DefaultLangSys);
4405 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4411 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4414 const GSUB_FeatureList *feature;
4415 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4417 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4418 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4420 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4421 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4423 const GSUB_Feature *feat;
4424 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4431 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4435 const GSUB_LookupList *lookup;
4436 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4438 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4439 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4441 const GSUB_LookupTable *look;
4442 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4443 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4444 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4445 if (GET_BE_WORD(look->LookupType) != 1)
4446 FIXME("We only handle SubType 1\n");
4451 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4453 const GSUB_SingleSubstFormat1 *ssf1;
4454 offset = GET_BE_WORD(look->SubTable[j]);
4455 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4456 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4458 int offset = GET_BE_WORD(ssf1->Coverage);
4459 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4460 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4462 TRACE(" Glyph 0x%x ->",glyph);
4463 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4464 TRACE(" 0x%x\n",glyph);
4469 const GSUB_SingleSubstFormat2 *ssf2;
4473 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4474 offset = GET_BE_WORD(ssf1->Coverage);
4475 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4476 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4477 TRACE(" Coverage index %i\n",index);
4480 TRACE(" Glyph is 0x%x ->",glyph);
4481 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4482 TRACE("0x%x\n",glyph);
4491 static const char* get_opentype_script(const GdiFont *font)
4494 * I am not sure if this is the correct way to generate our script tag
4497 switch (font->charset)
4499 case ANSI_CHARSET: return "latn";
4500 case BALTIC_CHARSET: return "latn"; /* ?? */
4501 case CHINESEBIG5_CHARSET: return "hani";
4502 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4503 case GB2312_CHARSET: return "hani";
4504 case GREEK_CHARSET: return "grek";
4505 case HANGUL_CHARSET: return "hang";
4506 case RUSSIAN_CHARSET: return "cyrl";
4507 case SHIFTJIS_CHARSET: return "kana";
4508 case TURKISH_CHARSET: return "latn"; /* ?? */
4509 case VIETNAMESE_CHARSET: return "latn";
4510 case JOHAB_CHARSET: return "latn"; /* ?? */
4511 case ARABIC_CHARSET: return "arab";
4512 case HEBREW_CHARSET: return "hebr";
4513 case THAI_CHARSET: return "thai";
4514 default: return "latn";
4518 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4520 const GSUB_Header *header;
4521 const GSUB_Script *script;
4522 const GSUB_LangSys *language;
4523 const GSUB_Feature *feature;
4525 if (!font->GSUB_Table)
4528 header = font->GSUB_Table;
4530 script = GSUB_get_script_table(header, get_opentype_script(font));
4533 TRACE("Script not found\n");
4536 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4539 TRACE("Language not found\n");
4542 feature = GSUB_get_feature(header, language, "vrt2");
4544 feature = GSUB_get_feature(header, language, "vert");
4547 TRACE("vrt2/vert feature not found\n");
4550 return GSUB_apply_feature(header, feature, glyph);
4553 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4557 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4558 WCHAR wc = (WCHAR)glyph;
4560 BOOL *default_used_pointer;
4563 default_used_pointer = NULL;
4564 default_used = FALSE;
4565 if (codepage_sets_default_used(font->codepage))
4566 default_used_pointer = &default_used;
4567 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4570 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4571 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4572 return get_GSUB_vert_glyph(font,ret);
4575 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4577 if (glyph < 0x100) glyph += 0xf000;
4578 /* there is a number of old pre-Unicode "broken" TTFs, which
4579 do have symbols at U+00XX instead of U+f0XX */
4580 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4581 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4583 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4585 return get_GSUB_vert_glyph(font,glyphId);
4588 /*************************************************************
4589 * WineEngGetGlyphIndices
4592 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4593 LPWORD pgi, DWORD flags)
4596 int default_char = -1;
4598 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4600 for(i = 0; i < count; i++)
4602 pgi[i] = get_glyph_index(font, lpstr[i]);
4605 if (default_char == -1)
4607 if (FT_IS_SFNT(font->ft_face))
4609 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4610 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4615 WineEngGetTextMetrics(font, &textm);
4616 default_char = textm.tmDefaultChar;
4619 pgi[i] = default_char;
4625 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4627 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4628 return !memcmp(matrix, &identity, sizeof(FMAT2));
4631 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4633 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4634 return !memcmp(matrix, &identity, sizeof(MAT2));
4637 /*************************************************************
4638 * WineEngGetGlyphOutline
4640 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4641 * except that the first parameter is the HWINEENGFONT of the font in
4642 * question rather than an HDC.
4645 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4646 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4649 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4650 FT_Face ft_face = incoming_font->ft_face;
4651 GdiFont *font = incoming_font;
4652 FT_UInt glyph_index;
4653 DWORD width, height, pitch, needed = 0;
4654 FT_Bitmap ft_bitmap;
4656 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4658 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4659 double widthRatio = 1.0;
4660 FT_Matrix transMat = identityMat;
4661 FT_Matrix transMatUnrotated;
4662 BOOL needsTransform = FALSE;
4663 BOOL tategaki = (font->GSUB_Table != NULL);
4664 UINT original_index;
4666 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4667 buflen, buf, lpmat);
4669 TRACE("font transform %f %f %f %f\n",
4670 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4671 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4674 EnterCriticalSection( &freetype_cs );
4676 if(format & GGO_GLYPH_INDEX) {
4677 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4678 original_index = glyph;
4679 format &= ~GGO_GLYPH_INDEX;
4681 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4682 ft_face = font->ft_face;
4683 original_index = glyph_index;
4686 if(format & GGO_UNHINTED) {
4687 load_flags |= FT_LOAD_NO_HINTING;
4688 format &= ~GGO_UNHINTED;
4691 /* tategaki never appears to happen to lower glyph index */
4692 if (glyph_index < TATEGAKI_LOWER_BOUND )
4695 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4696 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4697 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4698 font->gmsize * sizeof(GM*));
4700 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4701 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4703 *lpgm = FONT_GM(font,original_index)->gm;
4704 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4705 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4706 lpgm->gmCellIncX, lpgm->gmCellIncY);
4707 LeaveCriticalSection( &freetype_cs );
4708 return 1; /* FIXME */
4712 if (!font->gm[original_index / GM_BLOCK_SIZE])
4713 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4715 /* Scaling factor */
4720 WineEngGetTextMetrics(font, &tm);
4722 widthRatio = (double)font->aveWidth;
4723 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4726 widthRatio = font->scale_y;
4728 /* Scaling transform */
4729 if (widthRatio != 1.0 || font->scale_y != 1.0)
4732 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4735 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4737 pFT_Matrix_Multiply(&scaleMat, &transMat);
4738 needsTransform = TRUE;
4741 /* Slant transform */
4742 if (font->fake_italic) {
4745 slantMat.xx = (1 << 16);
4746 slantMat.xy = ((1 << 16) >> 2);
4748 slantMat.yy = (1 << 16);
4749 pFT_Matrix_Multiply(&slantMat, &transMat);
4750 needsTransform = TRUE;
4753 /* Rotation transform */
4754 transMatUnrotated = transMat;
4755 if(font->orientation && !tategaki) {
4756 FT_Matrix rotationMat;
4758 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4759 pFT_Vector_Unit(&vecAngle, angle);
4760 rotationMat.xx = vecAngle.x;
4761 rotationMat.xy = -vecAngle.y;
4762 rotationMat.yx = -rotationMat.xy;
4763 rotationMat.yy = rotationMat.xx;
4765 pFT_Matrix_Multiply(&rotationMat, &transMat);
4766 needsTransform = TRUE;
4769 /* World transform */
4770 if (!is_identity_FMAT2(&font->font_desc.matrix))
4773 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4774 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4775 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4776 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4777 pFT_Matrix_Multiply(&worldMat, &transMat);
4778 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4779 needsTransform = TRUE;
4782 /* Extra transformation specified by caller */
4783 if (!is_identity_MAT2(lpmat))
4786 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4787 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4788 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4789 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4790 pFT_Matrix_Multiply(&extraMat, &transMat);
4791 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4792 needsTransform = TRUE;
4795 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4796 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4797 format == GGO_GRAY8_BITMAP))
4799 load_flags |= FT_LOAD_NO_BITMAP;
4802 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4805 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4806 LeaveCriticalSection( &freetype_cs );
4810 if(!needsTransform) {
4811 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4812 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4813 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4815 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4816 bottom = (ft_face->glyph->metrics.horiBearingY -
4817 ft_face->glyph->metrics.height) & -64;
4818 lpgm->gmCellIncX = adv;
4819 lpgm->gmCellIncY = 0;
4826 for(xc = 0; xc < 2; xc++) {
4827 for(yc = 0; yc < 2; yc++) {
4828 vec.x = (ft_face->glyph->metrics.horiBearingX +
4829 xc * ft_face->glyph->metrics.width);
4830 vec.y = ft_face->glyph->metrics.horiBearingY -
4831 yc * ft_face->glyph->metrics.height;
4832 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4833 pFT_Vector_Transform(&vec, &transMat);
4834 if(xc == 0 && yc == 0) {
4835 left = right = vec.x;
4836 top = bottom = vec.y;
4838 if(vec.x < left) left = vec.x;
4839 else if(vec.x > right) right = vec.x;
4840 if(vec.y < bottom) bottom = vec.y;
4841 else if(vec.y > top) top = vec.y;
4846 right = (right + 63) & -64;
4847 bottom = bottom & -64;
4848 top = (top + 63) & -64;
4850 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4851 vec.x = ft_face->glyph->metrics.horiAdvance;
4853 pFT_Vector_Transform(&vec, &transMat);
4854 lpgm->gmCellIncX = (vec.x+63) >> 6;
4855 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4857 vec.x = ft_face->glyph->metrics.horiAdvance;
4859 pFT_Vector_Transform(&vec, &transMatUnrotated);
4860 adv = (vec.x+63) >> 6;
4864 bbx = (right - left) >> 6;
4865 lpgm->gmBlackBoxX = (right - left) >> 6;
4866 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4867 lpgm->gmptGlyphOrigin.x = left >> 6;
4868 lpgm->gmptGlyphOrigin.y = top >> 6;
4870 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4871 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4872 lpgm->gmCellIncX, lpgm->gmCellIncY);
4874 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4875 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4877 FONT_GM(font,original_index)->gm = *lpgm;
4878 FONT_GM(font,original_index)->adv = adv;
4879 FONT_GM(font,original_index)->lsb = lsb;
4880 FONT_GM(font,original_index)->bbx = bbx;
4881 FONT_GM(font,original_index)->init = TRUE;
4884 if(format == GGO_METRICS)
4886 LeaveCriticalSection( &freetype_cs );
4887 return 1; /* FIXME */
4890 if(ft_face->glyph->format != ft_glyph_format_outline &&
4891 (format == GGO_NATIVE || format == GGO_BEZIER ||
4892 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4893 format == GGO_GRAY8_BITMAP))
4895 TRACE("loaded a bitmap\n");
4896 LeaveCriticalSection( &freetype_cs );
4902 width = lpgm->gmBlackBoxX;
4903 height = lpgm->gmBlackBoxY;
4904 pitch = ((width + 31) >> 5) << 2;
4905 needed = pitch * height;
4907 if(!buf || !buflen) break;
4909 switch(ft_face->glyph->format) {
4910 case ft_glyph_format_bitmap:
4912 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4913 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4914 INT h = ft_face->glyph->bitmap.rows;
4916 memcpy(dst, src, w);
4917 src += ft_face->glyph->bitmap.pitch;
4923 case ft_glyph_format_outline:
4924 ft_bitmap.width = width;
4925 ft_bitmap.rows = height;
4926 ft_bitmap.pitch = pitch;
4927 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4928 ft_bitmap.buffer = buf;
4931 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4933 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4935 /* Note: FreeType will only set 'black' bits for us. */
4936 memset(buf, 0, needed);
4937 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4941 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4942 LeaveCriticalSection( &freetype_cs );
4947 case GGO_GRAY2_BITMAP:
4948 case GGO_GRAY4_BITMAP:
4949 case GGO_GRAY8_BITMAP:
4950 case WINE_GGO_GRAY16_BITMAP:
4952 unsigned int mult, row, col;
4955 width = lpgm->gmBlackBoxX;
4956 height = lpgm->gmBlackBoxY;
4957 pitch = (width + 3) / 4 * 4;
4958 needed = pitch * height;
4960 if(!buf || !buflen) break;
4962 switch(ft_face->glyph->format) {
4963 case ft_glyph_format_bitmap:
4965 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4966 INT h = ft_face->glyph->bitmap.rows;
4968 memset( buf, 0, needed );
4970 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
4971 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
4972 src += ft_face->glyph->bitmap.pitch;
4975 LeaveCriticalSection( &freetype_cs );
4978 case ft_glyph_format_outline:
4980 ft_bitmap.width = width;
4981 ft_bitmap.rows = height;
4982 ft_bitmap.pitch = pitch;
4983 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4984 ft_bitmap.buffer = buf;
4987 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4989 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4991 memset(ft_bitmap.buffer, 0, buflen);
4993 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4995 if(format == GGO_GRAY2_BITMAP)
4997 else if(format == GGO_GRAY4_BITMAP)
4999 else if(format == GGO_GRAY8_BITMAP)
5001 else /* format == WINE_GGO_GRAY16_BITMAP */
5003 LeaveCriticalSection( &freetype_cs );
5009 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5010 LeaveCriticalSection( &freetype_cs );
5015 for(row = 0; row < height; row++) {
5017 for(col = 0; col < width; col++, ptr++) {
5018 *ptr = (((int)*ptr) * mult + 128) / 256;
5025 case WINE_GGO_HRGB_BITMAP:
5026 case WINE_GGO_HBGR_BITMAP:
5027 case WINE_GGO_VRGB_BITMAP:
5028 case WINE_GGO_VBGR_BITMAP:
5029 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5031 switch (ft_face->glyph->format)
5033 case FT_GLYPH_FORMAT_BITMAP:
5038 width = lpgm->gmBlackBoxX;
5039 height = lpgm->gmBlackBoxY;
5041 needed = pitch * height;
5043 if (!buf || !buflen) break;
5045 memset(buf, 0, buflen);
5047 src = ft_face->glyph->bitmap.buffer;
5048 src_pitch = ft_face->glyph->bitmap.pitch;
5050 height = min( height, ft_face->glyph->bitmap.rows );
5053 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5055 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5056 ((unsigned int *)dst)[x] = ~0u;
5065 case FT_GLYPH_FORMAT_OUTLINE:
5069 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5070 INT x_shift, y_shift;
5072 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5073 FT_Render_Mode render_mode =
5074 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5075 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5077 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5079 if ( render_mode == FT_RENDER_MODE_LCD)
5081 lpgm->gmBlackBoxX += 2;
5082 lpgm->gmptGlyphOrigin.x -= 1;
5086 lpgm->gmBlackBoxY += 2;
5087 lpgm->gmptGlyphOrigin.y += 1;
5091 width = lpgm->gmBlackBoxX;
5092 height = lpgm->gmBlackBoxY;
5094 needed = pitch * height;
5096 if (!buf || !buflen) break;
5098 memset(buf, 0, buflen);
5100 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5102 if ( needsTransform )
5103 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5105 if ( pFT_Library_SetLcdFilter )
5106 pFT_Library_SetLcdFilter( library, lcdfilter );
5107 pFT_Render_Glyph (ft_face->glyph, render_mode);
5109 src = ft_face->glyph->bitmap.buffer;
5110 src_pitch = ft_face->glyph->bitmap.pitch;
5111 src_width = ft_face->glyph->bitmap.width;
5112 src_height = ft_face->glyph->bitmap.rows;
5114 if ( render_mode == FT_RENDER_MODE_LCD)
5122 rgb_interval = src_pitch;
5127 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5128 if ( x_shift < 0 ) x_shift = 0;
5129 if ( x_shift + (src_width / hmul) > width )
5130 x_shift = width - (src_width / hmul);
5132 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5133 if ( y_shift < 0 ) y_shift = 0;
5134 if ( y_shift + (src_height / vmul) > height )
5135 y_shift = height - (src_height / vmul);
5137 dst += x_shift + y_shift * ( pitch / 4 );
5138 while ( src_height )
5140 for ( x = 0; x < src_width / hmul; x++ )
5144 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5145 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5146 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5147 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5151 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5152 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5153 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5154 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5157 src += src_pitch * vmul;
5166 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5167 LeaveCriticalSection ( &freetype_cs );
5174 LeaveCriticalSection( &freetype_cs );
5180 int contour, point = 0, first_pt;
5181 FT_Outline *outline = &ft_face->glyph->outline;
5182 TTPOLYGONHEADER *pph;
5184 DWORD pph_start, cpfx, type;
5186 if(buflen == 0) buf = NULL;
5188 if (needsTransform && buf) {
5189 pFT_Outline_Transform(outline, &transMat);
5192 for(contour = 0; contour < outline->n_contours; contour++) {
5194 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5197 pph->dwType = TT_POLYGON_TYPE;
5198 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5200 needed += sizeof(*pph);
5202 while(point <= outline->contours[contour]) {
5203 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5204 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5205 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5209 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5212 } while(point <= outline->contours[contour] &&
5213 (outline->tags[point] & FT_Curve_Tag_On) ==
5214 (outline->tags[point-1] & FT_Curve_Tag_On));
5215 /* At the end of a contour Windows adds the start point, but
5217 if(point > outline->contours[contour] &&
5218 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5220 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5222 } else if(point <= outline->contours[contour] &&
5223 outline->tags[point] & FT_Curve_Tag_On) {
5224 /* add closing pt for bezier */
5226 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5234 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5237 pph->cb = needed - pph_start;
5243 /* Convert the quadratic Beziers to cubic Beziers.
5244 The parametric eqn for a cubic Bezier is, from PLRM:
5245 r(t) = at^3 + bt^2 + ct + r0
5246 with the control points:
5251 A quadratic Beizer has the form:
5252 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5254 So equating powers of t leads to:
5255 r1 = 2/3 p1 + 1/3 p0
5256 r2 = 2/3 p1 + 1/3 p2
5257 and of course r0 = p0, r3 = p2
5260 int contour, point = 0, first_pt;
5261 FT_Outline *outline = &ft_face->glyph->outline;
5262 TTPOLYGONHEADER *pph;
5264 DWORD pph_start, cpfx, type;
5265 FT_Vector cubic_control[4];
5266 if(buflen == 0) buf = NULL;
5268 if (needsTransform && buf) {
5269 pFT_Outline_Transform(outline, &transMat);
5272 for(contour = 0; contour < outline->n_contours; contour++) {
5274 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5277 pph->dwType = TT_POLYGON_TYPE;
5278 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5280 needed += sizeof(*pph);
5282 while(point <= outline->contours[contour]) {
5283 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5284 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5285 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5288 if(type == TT_PRIM_LINE) {
5290 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5294 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5297 /* FIXME: Possible optimization in endpoint calculation
5298 if there are two consecutive curves */
5299 cubic_control[0] = outline->points[point-1];
5300 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5301 cubic_control[0].x += outline->points[point].x + 1;
5302 cubic_control[0].y += outline->points[point].y + 1;
5303 cubic_control[0].x >>= 1;
5304 cubic_control[0].y >>= 1;
5306 if(point+1 > outline->contours[contour])
5307 cubic_control[3] = outline->points[first_pt];
5309 cubic_control[3] = outline->points[point+1];
5310 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5311 cubic_control[3].x += outline->points[point].x + 1;
5312 cubic_control[3].y += outline->points[point].y + 1;
5313 cubic_control[3].x >>= 1;
5314 cubic_control[3].y >>= 1;
5317 /* r1 = 1/3 p0 + 2/3 p1
5318 r2 = 1/3 p2 + 2/3 p1 */
5319 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5320 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5321 cubic_control[2] = cubic_control[1];
5322 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5323 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5324 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5325 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5327 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5328 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5329 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5334 } while(point <= outline->contours[contour] &&
5335 (outline->tags[point] & FT_Curve_Tag_On) ==
5336 (outline->tags[point-1] & FT_Curve_Tag_On));
5337 /* At the end of a contour Windows adds the start point,
5338 but only for Beziers and we've already done that.
5340 if(point <= outline->contours[contour] &&
5341 outline->tags[point] & FT_Curve_Tag_On) {
5342 /* This is the closing pt of a bezier, but we've already
5343 added it, so just inc point and carry on */
5350 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5353 pph->cb = needed - pph_start;
5359 FIXME("Unsupported format %d\n", format);
5360 LeaveCriticalSection( &freetype_cs );
5363 LeaveCriticalSection( &freetype_cs );
5367 static BOOL get_bitmap_text_metrics(GdiFont *font)
5369 FT_Face ft_face = font->ft_face;
5370 #ifdef HAVE_FREETYPE_FTWINFNT_H
5371 FT_WinFNT_HeaderRec winfnt_header;
5373 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5374 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5375 font->potm->otmSize = size;
5377 #define TM font->potm->otmTextMetrics
5378 #ifdef HAVE_FREETYPE_FTWINFNT_H
5379 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5381 TM.tmHeight = winfnt_header.pixel_height;
5382 TM.tmAscent = winfnt_header.ascent;
5383 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5384 TM.tmInternalLeading = winfnt_header.internal_leading;
5385 TM.tmExternalLeading = winfnt_header.external_leading;
5386 TM.tmAveCharWidth = winfnt_header.avg_width;
5387 TM.tmMaxCharWidth = winfnt_header.max_width;
5388 TM.tmWeight = winfnt_header.weight;
5390 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5391 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5392 TM.tmFirstChar = winfnt_header.first_char;
5393 TM.tmLastChar = winfnt_header.last_char;
5394 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5395 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5396 TM.tmItalic = winfnt_header.italic;
5397 TM.tmUnderlined = font->underline;
5398 TM.tmStruckOut = font->strikeout;
5399 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5400 TM.tmCharSet = winfnt_header.charset;
5405 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5406 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5407 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5408 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5409 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5410 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5411 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5412 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5414 TM.tmDigitizedAspectX = 96; /* FIXME */
5415 TM.tmDigitizedAspectY = 96; /* FIXME */
5417 TM.tmLastChar = 255;
5418 TM.tmDefaultChar = 32;
5419 TM.tmBreakChar = 32;
5420 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5421 TM.tmUnderlined = font->underline;
5422 TM.tmStruckOut = font->strikeout;
5423 /* NB inverted meaning of TMPF_FIXED_PITCH */
5424 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5425 TM.tmCharSet = font->charset;
5433 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5435 double scale_x, scale_y;
5439 scale_x = (double)font->aveWidth;
5440 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5443 scale_x = font->scale_y;
5445 scale_x *= fabs(font->font_desc.matrix.eM11);
5446 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5448 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5449 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5451 SCALE_Y(ptm->tmHeight);
5452 SCALE_Y(ptm->tmAscent);
5453 SCALE_Y(ptm->tmDescent);
5454 SCALE_Y(ptm->tmInternalLeading);
5455 SCALE_Y(ptm->tmExternalLeading);
5456 SCALE_Y(ptm->tmOverhang);
5458 SCALE_X(ptm->tmAveCharWidth);
5459 SCALE_X(ptm->tmMaxCharWidth);
5465 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5467 double scale_x, scale_y;
5471 scale_x = (double)font->aveWidth;
5472 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5475 scale_x = font->scale_y;
5477 scale_x *= fabs(font->font_desc.matrix.eM11);
5478 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5480 scale_font_metrics(font, &potm->otmTextMetrics);
5482 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5483 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5485 SCALE_Y(potm->otmAscent);
5486 SCALE_Y(potm->otmDescent);
5487 SCALE_Y(potm->otmLineGap);
5488 SCALE_Y(potm->otmsCapEmHeight);
5489 SCALE_Y(potm->otmsXHeight);
5490 SCALE_Y(potm->otmrcFontBox.top);
5491 SCALE_Y(potm->otmrcFontBox.bottom);
5492 SCALE_X(potm->otmrcFontBox.left);
5493 SCALE_X(potm->otmrcFontBox.right);
5494 SCALE_Y(potm->otmMacAscent);
5495 SCALE_Y(potm->otmMacDescent);
5496 SCALE_Y(potm->otmMacLineGap);
5497 SCALE_X(potm->otmptSubscriptSize.x);
5498 SCALE_Y(potm->otmptSubscriptSize.y);
5499 SCALE_X(potm->otmptSubscriptOffset.x);
5500 SCALE_Y(potm->otmptSubscriptOffset.y);
5501 SCALE_X(potm->otmptSuperscriptSize.x);
5502 SCALE_Y(potm->otmptSuperscriptSize.y);
5503 SCALE_X(potm->otmptSuperscriptOffset.x);
5504 SCALE_Y(potm->otmptSuperscriptOffset.y);
5505 SCALE_Y(potm->otmsStrikeoutSize);
5506 SCALE_Y(potm->otmsStrikeoutPosition);
5507 SCALE_Y(potm->otmsUnderscoreSize);
5508 SCALE_Y(potm->otmsUnderscorePosition);
5514 /*************************************************************
5515 * WineEngGetTextMetrics
5518 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5521 EnterCriticalSection( &freetype_cs );
5523 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5524 if(!get_bitmap_text_metrics(font))
5526 LeaveCriticalSection( &freetype_cs );
5530 /* Make sure that the font has sane width/height ratio */
5533 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5535 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5541 *ptm = font->potm->otmTextMetrics;
5542 scale_font_metrics(font, ptm);
5543 LeaveCriticalSection( &freetype_cs );
5547 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5551 for(i = 0; i < ft_face->num_charmaps; i++)
5553 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5559 /*************************************************************
5560 * WineEngGetOutlineTextMetrics
5563 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5564 OUTLINETEXTMETRICW *potm)
5566 FT_Face ft_face = font->ft_face;
5567 UINT needed, lenfam, lensty, ret;
5569 TT_HoriHeader *pHori;
5570 TT_Postscript *pPost;
5571 FT_Fixed x_scale, y_scale;
5572 WCHAR *family_nameW, *style_nameW;
5573 static const WCHAR spaceW[] = {' ', '\0'};
5575 INT ascent, descent;
5577 TRACE("font=%p\n", font);
5579 if(!FT_IS_SCALABLE(ft_face))
5583 EnterCriticalSection( &freetype_cs );
5586 if(cbSize >= font->potm->otmSize)
5588 memcpy(potm, font->potm, font->potm->otmSize);
5589 scale_outline_font_metrics(font, potm);
5591 LeaveCriticalSection( &freetype_cs );
5592 return font->potm->otmSize;
5596 needed = sizeof(*potm);
5598 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5599 family_nameW = strdupW(font->name);
5601 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5603 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5604 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5605 style_nameW, lensty/sizeof(WCHAR));
5607 /* These names should be read from the TT name table */
5609 /* length of otmpFamilyName */
5612 /* length of otmpFaceName */
5613 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5614 needed += lenfam; /* just the family name */
5616 needed += lenfam + lensty; /* family + " " + style */
5619 /* length of otmpStyleName */
5622 /* length of otmpFullName */
5623 needed += lenfam + lensty;
5626 x_scale = ft_face->size->metrics.x_scale;
5627 y_scale = ft_face->size->metrics.y_scale;
5629 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5631 FIXME("Can't find OS/2 table - not TT font?\n");
5636 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5638 FIXME("Can't find HHEA table - not TT font?\n");
5643 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5645 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",
5646 pOS2->usWinAscent, pOS2->usWinDescent,
5647 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5648 ft_face->ascender, ft_face->descender, ft_face->height,
5649 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5650 ft_face->bbox.yMax, ft_face->bbox.yMin);
5652 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5653 font->potm->otmSize = needed;
5655 #define TM font->potm->otmTextMetrics
5657 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5658 ascent = pHori->Ascender;
5659 descent = -pHori->Descender;
5661 ascent = pOS2->usWinAscent;
5662 descent = pOS2->usWinDescent;
5666 TM.tmAscent = font->yMax;
5667 TM.tmDescent = -font->yMin;
5668 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5670 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5671 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5672 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5673 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5676 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5679 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5681 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5682 ((ascent + descent) -
5683 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5685 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5686 if (TM.tmAveCharWidth == 0) {
5687 TM.tmAveCharWidth = 1;
5689 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5690 TM.tmWeight = FW_REGULAR;
5691 if (font->fake_bold)
5692 TM.tmWeight = FW_BOLD;
5695 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5697 if (pOS2->usWeightClass > FW_MEDIUM)
5698 TM.tmWeight = pOS2->usWeightClass;
5700 else if (pOS2->usWeightClass <= FW_MEDIUM)
5701 TM.tmWeight = pOS2->usWeightClass;
5704 TM.tmDigitizedAspectX = 300;
5705 TM.tmDigitizedAspectY = 300;
5706 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5707 * symbol range to 0 - f0ff
5710 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5715 case 1257: /* Baltic */
5716 TM.tmLastChar = 0xf8fd;
5719 TM.tmLastChar = 0xf0ff;
5721 TM.tmBreakChar = 0x20;
5722 TM.tmDefaultChar = 0x1f;
5726 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5727 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5729 if(pOS2->usFirstCharIndex <= 1)
5730 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5731 else if (pOS2->usFirstCharIndex > 0xff)
5732 TM.tmBreakChar = 0x20;
5734 TM.tmBreakChar = pOS2->usFirstCharIndex;
5735 TM.tmDefaultChar = TM.tmBreakChar - 1;
5737 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5738 TM.tmUnderlined = font->underline;
5739 TM.tmStruckOut = font->strikeout;
5741 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5742 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5743 (pOS2->version == 0xFFFFU ||
5744 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5745 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5747 TM.tmPitchAndFamily = 0;
5749 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5751 case PAN_FAMILY_SCRIPT:
5752 TM.tmPitchAndFamily |= FF_SCRIPT;
5755 case PAN_FAMILY_DECORATIVE:
5756 TM.tmPitchAndFamily |= FF_DECORATIVE;
5761 case PAN_FAMILY_TEXT_DISPLAY:
5762 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5763 /* which is clearly not what the panose spec says. */
5765 if(TM.tmPitchAndFamily == 0 || /* fixed */
5766 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5767 TM.tmPitchAndFamily = FF_MODERN;
5770 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5775 TM.tmPitchAndFamily |= FF_DONTCARE;
5778 case PAN_SERIF_COVE:
5779 case PAN_SERIF_OBTUSE_COVE:
5780 case PAN_SERIF_SQUARE_COVE:
5781 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5782 case PAN_SERIF_SQUARE:
5783 case PAN_SERIF_THIN:
5784 case PAN_SERIF_BONE:
5785 case PAN_SERIF_EXAGGERATED:
5786 case PAN_SERIF_TRIANGLE:
5787 TM.tmPitchAndFamily |= FF_ROMAN;
5790 case PAN_SERIF_NORMAL_SANS:
5791 case PAN_SERIF_OBTUSE_SANS:
5792 case PAN_SERIF_PERP_SANS:
5793 case PAN_SERIF_FLARED:
5794 case PAN_SERIF_ROUNDED:
5795 TM.tmPitchAndFamily |= FF_SWISS;
5802 if(FT_IS_SCALABLE(ft_face))
5803 TM.tmPitchAndFamily |= TMPF_VECTOR;
5805 if(FT_IS_SFNT(ft_face))
5807 if (font->ntmFlags & NTM_PS_OPENTYPE)
5808 TM.tmPitchAndFamily |= TMPF_DEVICE;
5810 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5813 TM.tmCharSet = font->charset;
5815 font->potm->otmFiller = 0;
5816 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5817 font->potm->otmfsSelection = pOS2->fsSelection;
5818 font->potm->otmfsType = pOS2->fsType;
5819 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5820 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5821 font->potm->otmItalicAngle = 0; /* POST table */
5822 font->potm->otmEMSquare = ft_face->units_per_EM;
5823 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5824 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5825 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5826 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5827 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5828 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5829 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5830 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5831 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5832 font->potm->otmMacAscent = TM.tmAscent;
5833 font->potm->otmMacDescent = -TM.tmDescent;
5834 font->potm->otmMacLineGap = font->potm->otmLineGap;
5835 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5836 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5837 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5838 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5839 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5840 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5841 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5842 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5843 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5844 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5845 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5847 font->potm->otmsUnderscoreSize = 0;
5848 font->potm->otmsUnderscorePosition = 0;
5850 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5851 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5855 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5856 cp = (char*)font->potm + sizeof(*font->potm);
5857 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5858 strcpyW((WCHAR*)cp, family_nameW);
5860 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5861 strcpyW((WCHAR*)cp, style_nameW);
5863 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5864 strcpyW((WCHAR*)cp, family_nameW);
5865 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5866 strcatW((WCHAR*)cp, spaceW);
5867 strcatW((WCHAR*)cp, style_nameW);
5868 cp += lenfam + lensty;
5871 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5872 strcpyW((WCHAR*)cp, family_nameW);
5873 strcatW((WCHAR*)cp, spaceW);
5874 strcatW((WCHAR*)cp, style_nameW);
5877 if(potm && needed <= cbSize)
5879 memcpy(potm, font->potm, font->potm->otmSize);
5880 scale_outline_font_metrics(font, potm);
5884 HeapFree(GetProcessHeap(), 0, style_nameW);
5885 HeapFree(GetProcessHeap(), 0, family_nameW);
5887 LeaveCriticalSection( &freetype_cs );
5891 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5893 HFONTLIST *hfontlist;
5894 child->font = alloc_font();
5895 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5896 if(!child->font->ft_face)
5898 free_font(child->font);
5903 child->font->font_desc = font->font_desc;
5904 child->font->ntmFlags = child->face->ntmFlags;
5905 child->font->orientation = font->orientation;
5906 child->font->scale_y = font->scale_y;
5907 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5908 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5909 child->font->name = strdupW(child->face->family->FamilyName);
5910 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5911 child->font->base_font = font;
5912 list_add_head(&child_font_list, &child->font->entry);
5913 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5917 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5920 CHILD_FONT *child_font;
5923 font = font->base_font;
5925 *linked_font = font;
5927 if((*glyph = get_glyph_index(font, c)))
5930 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5932 if(!child_font->font)
5933 if(!load_child_font(font, child_font))
5936 if(!child_font->font->ft_face)
5938 g = get_glyph_index(child_font->font, c);
5942 *linked_font = child_font->font;
5949 /*************************************************************
5950 * WineEngGetCharWidth
5953 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5956 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5959 FT_UInt glyph_index;
5960 GdiFont *linked_font;
5962 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5965 EnterCriticalSection( &freetype_cs );
5966 for(c = firstChar; c <= lastChar; c++) {
5967 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5968 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5969 &gm, 0, NULL, &identity);
5970 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5972 LeaveCriticalSection( &freetype_cs );
5976 /*************************************************************
5977 * WineEngGetCharABCWidths
5980 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5983 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5986 FT_UInt glyph_index;
5987 GdiFont *linked_font;
5989 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5991 if(!FT_IS_SCALABLE(font->ft_face))
5995 EnterCriticalSection( &freetype_cs );
5997 for(c = firstChar; c <= lastChar; c++) {
5998 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5999 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6000 &gm, 0, NULL, &identity);
6001 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6002 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6003 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6004 FONT_GM(linked_font,glyph_index)->bbx;
6006 LeaveCriticalSection( &freetype_cs );
6010 /*************************************************************
6011 * WineEngGetCharABCWidthsFloat
6014 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6016 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6019 FT_UInt glyph_index;
6020 GdiFont *linked_font;
6022 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6025 EnterCriticalSection( &freetype_cs );
6027 for (c = first; c <= last; c++)
6029 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6030 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6031 &gm, 0, NULL, &identity);
6032 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6033 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6034 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6035 FONT_GM(linked_font, glyph_index)->lsb -
6036 FONT_GM(linked_font, glyph_index)->bbx;
6038 LeaveCriticalSection( &freetype_cs );
6042 /*************************************************************
6043 * WineEngGetCharABCWidthsI
6046 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6049 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6052 FT_UInt glyph_index;
6053 GdiFont *linked_font;
6055 if(!FT_HAS_HORIZONTAL(font->ft_face))
6059 EnterCriticalSection( &freetype_cs );
6061 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6063 for(c = firstChar; c < firstChar+count; c++) {
6064 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6065 &gm, 0, NULL, &identity);
6066 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6067 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6068 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6069 - FONT_GM(linked_font,c)->bbx;
6072 for(c = 0; c < count; c++) {
6073 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6074 &gm, 0, NULL, &identity);
6075 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6076 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6077 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6078 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6081 LeaveCriticalSection( &freetype_cs );
6085 /*************************************************************
6086 * WineEngGetTextExtentExPoint
6089 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6090 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6092 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6097 FT_UInt glyph_index;
6098 GdiFont *linked_font;
6100 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6104 EnterCriticalSection( &freetype_cs );
6107 WineEngGetTextMetrics(font, &tm);
6108 size->cy = tm.tmHeight;
6110 for(idx = 0; idx < count; idx++) {
6111 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6112 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6113 &gm, 0, NULL, &identity);
6114 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6116 if (! pnfit || ext <= max_ext) {
6126 LeaveCriticalSection( &freetype_cs );
6127 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6131 /*************************************************************
6132 * WineEngGetTextExtentExPointI
6135 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6136 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6138 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6144 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6147 EnterCriticalSection( &freetype_cs );
6150 WineEngGetTextMetrics(font, &tm);
6151 size->cy = tm.tmHeight;
6153 for(idx = 0; idx < count; idx++) {
6154 WineEngGetGlyphOutline(font, indices[idx],
6155 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6157 size->cx += FONT_GM(font,indices[idx])->adv;
6159 if (! pnfit || ext <= max_ext) {
6169 LeaveCriticalSection( &freetype_cs );
6170 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6174 /*************************************************************
6175 * WineEngGetFontData
6178 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6181 FT_Face ft_face = font->ft_face;
6185 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6186 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6187 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6189 if(!FT_IS_SFNT(ft_face))
6197 if(table) { /* MS tags differ in endianness from FT ones */
6198 table = table >> 24 | table << 24 |
6199 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6202 /* make sure value of len is the value freetype says it needs */
6205 FT_ULong needed = 0;
6206 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6207 if( !err && needed < len) len = needed;
6209 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6212 TRACE("Can't find table %c%c%c%c\n",
6213 /* bytes were reversed */
6214 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6215 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6221 /*************************************************************
6222 * WineEngGetTextFace
6225 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6227 INT n = strlenW(font->name) + 1;
6229 lstrcpynW(str, font->name, count);
6230 return min(count, n);
6235 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6237 if (fs) *fs = font->fs;
6238 return font->charset;
6241 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6243 GdiFont *font = dc->gdiFont, *linked_font;
6244 struct list *first_hfont;
6248 EnterCriticalSection( &freetype_cs );
6249 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6250 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6251 if(font == linked_font)
6252 *new_hfont = dc->hFont;
6255 first_hfont = list_head(&linked_font->hfontlist);
6256 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6258 LeaveCriticalSection( &freetype_cs );
6262 /* Retrieve a list of supported Unicode ranges for a given font.
6263 * Can be called with NULL gs to calculate the buffer size. Returns
6264 * the number of ranges found.
6266 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6268 DWORD num_ranges = 0;
6270 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6273 FT_ULong char_code, char_code_prev;
6276 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6278 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6279 face->num_glyphs, glyph_code, char_code);
6281 if (!glyph_code) return 0;
6285 gs->ranges[0].wcLow = (USHORT)char_code;
6286 gs->ranges[0].cGlyphs = 0;
6287 gs->cGlyphsSupported = 0;
6293 if (char_code < char_code_prev)
6295 ERR("expected increasing char code from FT_Get_Next_Char\n");
6298 if (char_code - char_code_prev > 1)
6303 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6304 gs->ranges[num_ranges - 1].cGlyphs = 1;
6305 gs->cGlyphsSupported++;
6310 gs->ranges[num_ranges - 1].cGlyphs++;
6311 gs->cGlyphsSupported++;
6313 char_code_prev = char_code;
6314 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6318 FIXME("encoding %u not supported\n", face->charmap->encoding);
6323 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6326 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6328 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6331 glyphset->cbThis = size;
6332 glyphset->cRanges = num_ranges;
6333 glyphset->flAccel = 0;
6338 /*************************************************************
6341 BOOL WineEngFontIsLinked(GdiFont *font)
6345 EnterCriticalSection( &freetype_cs );
6346 ret = !list_empty(&font->child_fonts);
6347 LeaveCriticalSection( &freetype_cs );
6351 static BOOL is_hinting_enabled(void)
6353 /* Use the >= 2.2.0 function if available */
6354 if(pFT_Get_TrueType_Engine_Type)
6356 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6357 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6359 #ifdef FT_DRIVER_HAS_HINTER
6364 /* otherwise if we've been compiled with < 2.2.0 headers
6365 use the internal macro */
6366 mod = pFT_Get_Module(library, "truetype");
6367 if(mod && FT_DRIVER_HAS_HINTER(mod))
6375 static BOOL is_subpixel_rendering_enabled( void )
6377 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6378 return pFT_Library_SetLcdFilter &&
6379 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6385 /*************************************************************************
6386 * GetRasterizerCaps (GDI32.@)
6388 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6390 static int hinting = -1;
6391 static int subpixel = -1;
6395 hinting = is_hinting_enabled();
6396 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6399 if ( subpixel == -1 )
6401 subpixel = is_subpixel_rendering_enabled();
6402 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6405 lprs->nSize = sizeof(RASTERIZER_STATUS);
6406 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6408 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6409 lprs->nLanguageID = 0;
6413 /*************************************************************
6414 * WineEngRealizationInfo
6416 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6418 FIXME("(%p, %p): stub!\n", font, info);
6421 if(FT_IS_SCALABLE(font->ft_face))
6424 info->cache_num = font->cache_num;
6425 info->unknown2 = -1;
6429 /*************************************************************************
6430 * Kerning support for TrueType fonts
6432 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6434 struct TT_kern_table
6440 struct TT_kern_subtable
6449 USHORT horizontal : 1;
6451 USHORT cross_stream: 1;
6452 USHORT override : 1;
6453 USHORT reserved1 : 4;
6459 struct TT_format0_kern_subtable
6463 USHORT entrySelector;
6474 static DWORD parse_format0_kern_subtable(GdiFont *font,
6475 const struct TT_format0_kern_subtable *tt_f0_ks,
6476 const USHORT *glyph_to_char,
6477 KERNINGPAIR *kern_pair, DWORD cPairs)
6480 const struct TT_kern_pair *tt_kern_pair;
6482 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6484 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6486 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6487 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6488 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6490 if (!kern_pair || !cPairs)
6493 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6495 nPairs = min(nPairs, cPairs);
6497 for (i = 0; i < nPairs; i++)
6499 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6500 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6501 /* this algorithm appears to better match what Windows does */
6502 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6503 if (kern_pair->iKernAmount < 0)
6505 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6506 kern_pair->iKernAmount -= font->ppem;
6508 else if (kern_pair->iKernAmount > 0)
6510 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6511 kern_pair->iKernAmount += font->ppem;
6513 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6515 TRACE("left %u right %u value %d\n",
6516 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6520 TRACE("copied %u entries\n", nPairs);
6524 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6528 const struct TT_kern_table *tt_kern_table;
6529 const struct TT_kern_subtable *tt_kern_subtable;
6531 USHORT *glyph_to_char;
6534 EnterCriticalSection( &freetype_cs );
6535 if (font->total_kern_pairs != (DWORD)-1)
6537 if (cPairs && kern_pair)
6539 cPairs = min(cPairs, font->total_kern_pairs);
6540 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6541 LeaveCriticalSection( &freetype_cs );
6544 LeaveCriticalSection( &freetype_cs );
6545 return font->total_kern_pairs;
6548 font->total_kern_pairs = 0;
6550 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6552 if (length == GDI_ERROR)
6554 TRACE("no kerning data in the font\n");
6555 LeaveCriticalSection( &freetype_cs );
6559 buf = HeapAlloc(GetProcessHeap(), 0, length);
6562 WARN("Out of memory\n");
6563 LeaveCriticalSection( &freetype_cs );
6567 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6569 /* build a glyph index to char code map */
6570 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6573 WARN("Out of memory allocating a glyph index to char code map\n");
6574 HeapFree(GetProcessHeap(), 0, buf);
6575 LeaveCriticalSection( &freetype_cs );
6579 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6585 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6587 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6588 font->ft_face->num_glyphs, glyph_code, char_code);
6592 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6594 /* FIXME: This doesn't match what Windows does: it does some fancy
6595 * things with duplicate glyph index to char code mappings, while
6596 * we just avoid overriding existing entries.
6598 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6599 glyph_to_char[glyph_code] = (USHORT)char_code;
6601 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6608 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6609 for (n = 0; n <= 65535; n++)
6610 glyph_to_char[n] = (USHORT)n;
6613 tt_kern_table = buf;
6614 nTables = GET_BE_WORD(tt_kern_table->nTables);
6615 TRACE("version %u, nTables %u\n",
6616 GET_BE_WORD(tt_kern_table->version), nTables);
6618 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6620 for (i = 0; i < nTables; i++)
6622 struct TT_kern_subtable tt_kern_subtable_copy;
6624 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6625 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6626 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6628 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6629 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6630 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6632 /* According to the TrueType specification this is the only format
6633 * that will be properly interpreted by Windows and OS/2
6635 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6637 DWORD new_chunk, old_total = font->total_kern_pairs;
6639 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6640 glyph_to_char, NULL, 0);
6641 font->total_kern_pairs += new_chunk;
6643 if (!font->kern_pairs)
6644 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6645 font->total_kern_pairs * sizeof(*font->kern_pairs));
6647 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6648 font->total_kern_pairs * sizeof(*font->kern_pairs));
6650 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6651 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6654 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6656 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6659 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6660 HeapFree(GetProcessHeap(), 0, buf);
6662 if (cPairs && kern_pair)
6664 cPairs = min(cPairs, font->total_kern_pairs);
6665 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6666 LeaveCriticalSection( &freetype_cs );
6669 LeaveCriticalSection( &freetype_cs );
6670 return font->total_kern_pairs;
6673 #else /* HAVE_FREETYPE */
6675 /*************************************************************************/
6677 BOOL WineEngInit(void)
6681 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6685 BOOL WineEngDestroyFontInstance(HFONT hfont)
6690 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6695 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6696 LPWORD pgi, DWORD flags)
6701 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6702 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6705 ERR("called but we don't have FreeType\n");
6709 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6711 ERR("called but we don't have FreeType\n");
6715 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6716 OUTLINETEXTMETRICW *potm)
6718 ERR("called but we don't have FreeType\n");
6722 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6725 ERR("called but we don't have FreeType\n");
6729 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6732 ERR("called but we don't have FreeType\n");
6736 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6738 ERR("called but we don't have FreeType\n");
6742 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6745 ERR("called but we don't have FreeType\n");
6749 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6750 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6752 ERR("called but we don't have FreeType\n");
6756 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6757 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6759 ERR("called but we don't have FreeType\n");
6763 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6766 ERR("called but we don't have FreeType\n");
6770 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6772 ERR("called but we don't have FreeType\n");
6776 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6778 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6782 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6784 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6788 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6790 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6794 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6796 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6797 return DEFAULT_CHARSET;
6800 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6805 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6807 FIXME("(%p, %p): stub\n", font, glyphset);
6811 BOOL WineEngFontIsLinked(GdiFont *font)
6816 /*************************************************************************
6817 * GetRasterizerCaps (GDI32.@)
6819 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6821 lprs->nSize = sizeof(RASTERIZER_STATUS);
6823 lprs->nLanguageID = 0;
6827 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6829 ERR("called but we don't have FreeType\n");
6833 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6835 ERR("called but we don't have FreeType\n");
6839 #endif /* HAVE_FREETYPE */