2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FT2BUILD_H
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
120 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
121 #include <freetype/internal/sfnt.h>
123 #ifdef HAVE_FREETYPE_FTTRIGON_H
124 #include <freetype/fttrigon.h>
126 #ifdef HAVE_FREETYPE_FTWINFNT_H
127 #include <freetype/ftwinfnt.h>
129 #ifdef HAVE_FREETYPE_FTMODAPI_H
130 #include <freetype/ftmodapi.h>
132 #ifdef HAVE_FREETYPE_FTLCDFIL_H
133 #include <freetype/ftlcdfil.h>
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
139 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType;
145 static FT_Library library = 0;
152 static FT_Version_t FT_Version;
153 static DWORD FT_SimpleVersion;
155 static void *ft_handle = NULL;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Vector_Unit);
159 MAKE_FUNCPTR(FT_Done_Face);
160 MAKE_FUNCPTR(FT_Get_Char_Index);
161 MAKE_FUNCPTR(FT_Get_Module);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Init_FreeType);
166 MAKE_FUNCPTR(FT_Load_Glyph);
167 MAKE_FUNCPTR(FT_Matrix_Multiply);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
171 MAKE_FUNCPTR(FT_MulFix);
173 MAKE_FUNCPTR(FT_New_Face);
174 MAKE_FUNCPTR(FT_New_Memory_Face);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
176 MAKE_FUNCPTR(FT_Outline_Transform);
177 MAKE_FUNCPTR(FT_Outline_Translate);
178 MAKE_FUNCPTR(FT_Select_Charmap);
179 MAKE_FUNCPTR(FT_Set_Charmap);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
181 MAKE_FUNCPTR(FT_Vector_Transform);
182 MAKE_FUNCPTR(FT_Render_Glyph);
183 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
184 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
185 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
186 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
191 #ifdef HAVE_FREETYPE_FTWINFNT_H
192 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
195 #ifdef SONAME_LIBFONTCONFIG
196 #include <fontconfig/fontconfig.h>
197 MAKE_FUNCPTR(FcConfigGetCurrent);
198 MAKE_FUNCPTR(FcFontList);
199 MAKE_FUNCPTR(FcFontSetDestroy);
200 MAKE_FUNCPTR(FcInit);
201 MAKE_FUNCPTR(FcObjectSetAdd);
202 MAKE_FUNCPTR(FcObjectSetCreate);
203 MAKE_FUNCPTR(FcObjectSetDestroy);
204 MAKE_FUNCPTR(FcPatternCreate);
205 MAKE_FUNCPTR(FcPatternDestroy);
206 MAKE_FUNCPTR(FcPatternGetBool);
207 MAKE_FUNCPTR(FcPatternGetString);
213 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
214 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
215 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
218 #ifndef ft_encoding_none
219 #define FT_ENCODING_NONE ft_encoding_none
221 #ifndef ft_encoding_ms_symbol
222 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
224 #ifndef ft_encoding_unicode
225 #define FT_ENCODING_UNICODE ft_encoding_unicode
227 #ifndef ft_encoding_apple_roman
228 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
231 #ifdef WORDS_BIGENDIAN
232 #define GET_BE_WORD(x) (x)
234 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
237 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
244 FT_Short internal_leading;
247 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
248 So to let this compile on older versions of FreeType we'll define the
249 new structure here. */
251 FT_Short height, width;
252 FT_Pos size, x_ppem, y_ppem;
258 NEWTEXTMETRICEXW ntm;
262 typedef struct tagFace {
267 DWORD font_data_size;
270 FONTSIGNATURE fs_links;
272 FT_Fixed font_version;
274 Bitmap_Size size; /* set if face is a bitmap */
275 BOOL external; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily *family;
277 /* Cached data for Enum */
278 struct enum_data *cached_enum_data;
281 typedef struct tagFamily {
283 const WCHAR *FamilyName;
289 INT adv; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST {
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping *mapping;
353 const WCHAR *font_name;
357 #define GM_BLOCK_SIZE 128
358 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
360 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
361 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
362 #define UNUSED_CACHE_SIZE 10
363 static struct list child_font_list = LIST_INIT(child_font_list);
364 static struct list system_links = LIST_INIT(system_links);
366 static struct list font_subst_list = LIST_INIT(font_subst_list);
368 static struct list font_list = LIST_INIT(font_list);
370 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
371 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
372 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
374 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
375 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
376 'W','i','n','d','o','w','s','\\',
377 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
378 'F','o','n','t','s','\0'};
380 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
381 'W','i','n','d','o','w','s',' ','N','T','\\',
382 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
383 'F','o','n','t','s','\0'};
385 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
386 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
387 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
388 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
390 static const WCHAR * const SystemFontValues[4] = {
397 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
398 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
400 /* Interesting and well-known (frequently-assumed!) font names */
401 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
402 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 };
403 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
404 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
405 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
406 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
407 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
408 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
410 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
411 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
412 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
413 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
414 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
415 'E','u','r','o','p','e','a','n','\0'};
416 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
417 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
418 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
419 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
420 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
421 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
422 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
423 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
424 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
425 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
426 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
427 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
429 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
439 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
447 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
456 typedef struct tagFontSubst {
472 static struct list mappings_list = LIST_INIT( mappings_list );
474 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
476 static CRITICAL_SECTION freetype_cs;
477 static CRITICAL_SECTION_DEBUG critsect_debug =
480 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
481 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
483 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
485 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
487 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
488 static BOOL use_default_fallback = FALSE;
490 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
492 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
493 'W','i','n','d','o','w','s',' ','N','T','\\',
494 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
495 'S','y','s','t','e','m','L','i','n','k',0};
497 /****************************************
498 * Notes on .fon files
500 * The fonts System, FixedSys and Terminal are special. There are typically multiple
501 * versions installed for different resolutions and codepages. Windows stores which one to use
502 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
504 * FIXEDFON.FON FixedSys
506 * OEMFONT.FON Terminal
507 * LogPixels Current dpi set by the display control panel applet
508 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
509 * also has a LogPixels value that appears to mirror this)
511 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
512 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
513 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
514 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
515 * so that makes sense.
517 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
518 * to be mapped into the registry on Windows 2000 at least).
521 * ega80woa.fon=ega80850.fon
522 * ega40woa.fon=ega40850.fon
523 * cga80woa.fon=cga80850.fon
524 * cga40woa.fon=cga40850.fon
527 /* These are all structures needed for the GSUB table */
529 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
530 #define TATEGAKI_LOWER_BOUND 0x02F1
546 GSUB_ScriptRecord ScriptRecord[1];
552 } GSUB_LangSysRecord;
557 GSUB_LangSysRecord LangSysRecord[1];
561 WORD LookupOrder; /* Reserved */
562 WORD ReqFeatureIndex;
564 WORD FeatureIndex[1];
570 } GSUB_FeatureRecord;
574 GSUB_FeatureRecord FeatureRecord[1];
578 WORD FeatureParams; /* Reserved */
580 WORD LookupListIndex[1];
599 } GSUB_CoverageFormat1;
604 WORD StartCoverageIndex;
610 GSUB_RangeRecord RangeRecord[1];
611 } GSUB_CoverageFormat2;
614 WORD SubstFormat; /* = 1 */
617 } GSUB_SingleSubstFormat1;
620 WORD SubstFormat; /* = 2 */
624 }GSUB_SingleSubstFormat2;
626 #ifdef HAVE_CARBON_CARBON_H
627 static char *find_cache_dir(void)
631 static char cached_path[MAX_PATH];
632 static const char *wine = "/Wine", *fonts = "/Fonts";
634 if(*cached_path) return cached_path;
636 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
639 WARN("can't create cached data folder\n");
642 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
645 WARN("can't create cached data path\n");
649 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
651 ERR("Could not create full path\n");
655 strcat(cached_path, wine);
657 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
659 WARN("Couldn't mkdir %s\n", cached_path);
663 strcat(cached_path, fonts);
664 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
666 WARN("Couldn't mkdir %s\n", cached_path);
673 /******************************************************************
676 * Extracts individual TrueType font files from a Mac suitcase font
677 * and saves them into the user's caches directory (see
679 * Returns a NULL terminated array of filenames.
681 * We do this because they are apps that try to read ttf files
682 * themselves and they don't like Mac suitcase files.
684 static char **expand_mac_font(const char *path)
691 const char *filename;
695 unsigned int size, max_size;
698 TRACE("path %s\n", path);
700 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
703 WARN("failed to get ref\n");
707 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
710 TRACE("no data fork, so trying resource fork\n");
711 res_ref = FSOpenResFile(&ref, fsRdPerm);
714 TRACE("unable to open resource fork\n");
721 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
724 CloseResFile(res_ref);
728 out_dir = find_cache_dir();
730 filename = strrchr(path, '/');
731 if(!filename) filename = path;
734 /* output filename has the form out_dir/filename_%04x.ttf */
735 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
742 unsigned short *num_faces_ptr, num_faces, face;
745 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
747 fond = Get1IndResource(fond_res, idx);
749 TRACE("got fond resource %d\n", idx);
752 fam_rec = *(FamRec**)fond;
753 num_faces_ptr = (unsigned short *)(fam_rec + 1);
754 num_faces = GET_BE_WORD(*num_faces_ptr);
756 assoc = (AsscEntry*)(num_faces_ptr + 1);
757 TRACE("num faces %04x\n", num_faces);
758 for(face = 0; face < num_faces; face++, assoc++)
761 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
762 unsigned short size, font_id;
765 size = GET_BE_WORD(assoc->fontSize);
766 font_id = GET_BE_WORD(assoc->fontID);
769 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
773 TRACE("trying to load sfnt id %04x\n", font_id);
774 sfnt = GetResource(sfnt_res, font_id);
777 TRACE("can't get sfnt resource %04x\n", font_id);
781 output = HeapAlloc(GetProcessHeap(), 0, output_len);
786 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
788 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
789 if(fd != -1 || errno == EEXIST)
793 unsigned char *sfnt_data;
796 sfnt_data = *(unsigned char**)sfnt;
797 write(fd, sfnt_data, GetHandleSize(sfnt));
801 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
804 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
806 ret.array[ret.size++] = output;
810 WARN("unable to create %s\n", output);
811 HeapFree(GetProcessHeap(), 0, output);
814 ReleaseResource(sfnt);
817 ReleaseResource(fond);
820 CloseResFile(res_ref);
825 #endif /* HAVE_CARBON_CARBON_H */
827 static inline BOOL is_win9x(void)
829 return GetVersion() & 0x80000000;
832 This function builds an FT_Fixed from a double. It fails if the absolute
833 value of the float number is greater than 32768.
835 static inline FT_Fixed FT_FixedFromFloat(double f)
841 This function builds an FT_Fixed from a FIXED. It simply put f.value
842 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
844 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
846 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
850 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
855 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
856 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
858 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
859 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
861 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
863 if(face_name && strcmpiW(face_name, family->FamilyName))
865 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
869 file = strrchr(face->file, '/');
874 if(!strcasecmp(file, file_nameA))
876 HeapFree(GetProcessHeap(), 0, file_nameA);
881 HeapFree(GetProcessHeap(), 0, file_nameA);
885 static Family *find_family_from_name(const WCHAR *name)
889 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
891 if(!strcmpiW(family->FamilyName, name))
898 static void DumpSubstList(void)
902 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
904 if(psub->from.charset != -1 || psub->to.charset != -1)
905 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
906 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
908 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
909 debugstr_w(psub->to.name));
914 static LPWSTR strdupW(LPCWSTR p)
917 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
918 ret = HeapAlloc(GetProcessHeap(), 0, len);
923 static LPSTR strdupA(LPCSTR p)
926 DWORD len = (strlen(p) + 1);
927 ret = HeapAlloc(GetProcessHeap(), 0, len);
932 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
937 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
939 if(!strcmpiW(element->from.name, from_name) &&
940 (element->from.charset == from_charset ||
941 element->from.charset == -1))
948 #define ADD_FONT_SUBST_FORCE 1
950 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
952 FontSubst *from_exist, *to_exist;
954 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
956 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
958 list_remove(&from_exist->entry);
959 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
960 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
961 HeapFree(GetProcessHeap(), 0, from_exist);
967 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
971 HeapFree(GetProcessHeap(), 0, subst->to.name);
972 subst->to.name = strdupW(to_exist->to.name);
975 list_add_tail(subst_list, &subst->entry);
980 HeapFree(GetProcessHeap(), 0, subst->from.name);
981 HeapFree(GetProcessHeap(), 0, subst->to.name);
982 HeapFree(GetProcessHeap(), 0, subst);
986 static void split_subst_info(NameCs *nc, LPSTR str)
988 CHAR *p = strrchr(str, ',');
993 nc->charset = strtol(p+1, NULL, 10);
996 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
997 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
998 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1001 static void LoadSubstList(void)
1005 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1009 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1010 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1011 &hkey) == ERROR_SUCCESS) {
1013 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1014 &valuelen, &datalen, NULL, NULL);
1016 valuelen++; /* returned value doesn't include room for '\0' */
1017 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1018 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1022 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1023 &dlen) == ERROR_SUCCESS) {
1024 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1026 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1027 split_subst_info(&psub->from, value);
1028 split_subst_info(&psub->to, data);
1030 /* Win 2000 doesn't allow mapping between different charsets
1031 or mapping of DEFAULT_CHARSET */
1032 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1033 psub->to.charset == DEFAULT_CHARSET) {
1034 HeapFree(GetProcessHeap(), 0, psub->to.name);
1035 HeapFree(GetProcessHeap(), 0, psub->from.name);
1036 HeapFree(GetProcessHeap(), 0, psub);
1038 add_font_subst(&font_subst_list, psub, 0);
1040 /* reset dlen and vlen */
1044 HeapFree(GetProcessHeap(), 0, data);
1045 HeapFree(GetProcessHeap(), 0, value);
1051 /*****************************************************************
1052 * get_name_table_entry
1054 * Supply the platform, encoding, language and name ids in req
1055 * and if the name exists the function will fill in the string
1056 * and string_len members. The string is owned by FreeType so
1057 * don't free it. Returns TRUE if the name is found else FALSE.
1059 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1062 FT_UInt num_names, name_index;
1064 if(FT_IS_SFNT(ft_face))
1066 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1068 for(name_index = 0; name_index < num_names; name_index++)
1070 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1072 if((name.platform_id == req->platform_id) &&
1073 (name.encoding_id == req->encoding_id) &&
1074 (name.language_id == req->language_id) &&
1075 (name.name_id == req->name_id))
1077 req->string = name.string;
1078 req->string_len = name.string_len;
1085 req->string_len = 0;
1089 static WCHAR *get_familyname(FT_Face ft_face)
1091 WCHAR *family = NULL;
1094 name.platform_id = TT_PLATFORM_MICROSOFT;
1095 name.encoding_id = TT_MS_ID_UNICODE_CS;
1096 name.language_id = GetUserDefaultLCID();
1097 name.name_id = TT_NAME_ID_FONT_FAMILY;
1099 if(get_name_table_entry(ft_face, &name))
1103 /* String is not nul terminated and string_len is a byte length. */
1104 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1105 for(i = 0; i < name.string_len / 2; i++)
1107 WORD *tmp = (WORD *)&name.string[i * 2];
1108 family[i] = GET_BE_WORD(*tmp);
1111 TRACE("Got localised name %s\n", debugstr_w(family));
1118 /*****************************************************************
1121 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1122 * of FreeType that don't export this function.
1125 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1130 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1131 if(pFT_Load_Sfnt_Table)
1133 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1135 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1136 else /* Do it the hard way */
1138 TT_Face tt_face = (TT_Face) ft_face;
1139 SFNT_Interface *sfnt;
1140 if (FT_Version.major==2 && FT_Version.minor==0)
1143 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1147 /* A field was added in the middle of the structure in 2.1.x */
1148 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1150 err = sfnt->load_any(tt_face, table, offset, buf, len);
1158 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1159 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1160 "Please upgrade your freetype library.\n");
1163 err = FT_Err_Unimplemented_Feature;
1169 static inline int TestStyles(DWORD flags, DWORD styles)
1171 return (flags & styles) == styles;
1174 static int StyleOrdering(Face *face)
1176 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1178 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1180 if (TestStyles(face->ntmFlags, NTM_BOLD))
1182 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1185 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1186 debugstr_w(face->family->FamilyName),
1187 debugstr_w(face->StyleName),
1193 /* Add a style of face to a font family using an ordering of the list such
1194 that regular fonts come before bold and italic, and single styles come
1195 before compound styles. */
1196 static void AddFaceToFamily(Face *face, Family *family)
1200 LIST_FOR_EACH( entry, &family->faces )
1202 Face *ent = LIST_ENTRY(entry, Face, entry);
1203 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1205 list_add_before( entry, &face->entry );
1208 #define ADDFONT_EXTERNAL_FONT 0x01
1209 #define ADDFONT_FORCE_BITMAP 0x02
1210 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1214 TT_Header *pHeader = NULL;
1215 WCHAR *english_family, *localised_family, *StyleW;
1219 struct list *family_elem_ptr, *face_elem_ptr;
1221 FT_Long face_index = 0, num_faces;
1222 #ifdef HAVE_FREETYPE_FTWINFNT_H
1223 FT_WinFNT_HeaderRec winfnt_header;
1225 int i, bitmap_num, internal_leading;
1228 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1229 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1231 #ifdef HAVE_CARBON_CARBON_H
1232 if(file && !fake_family)
1234 char **mac_list = expand_mac_font(file);
1237 BOOL had_one = FALSE;
1239 for(cursor = mac_list; *cursor; cursor++)
1242 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1243 HeapFree(GetProcessHeap(), 0, *cursor);
1245 HeapFree(GetProcessHeap(), 0, mac_list);
1250 #endif /* HAVE_CARBON_CARBON_H */
1253 char *family_name = fake_family;
1257 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1258 err = pFT_New_Face(library, file, face_index, &ft_face);
1261 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1262 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1266 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1270 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*/
1271 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1272 pFT_Done_Face(ft_face);
1276 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1277 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1278 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1279 pFT_Done_Face(ft_face);
1283 if(FT_IS_SFNT(ft_face))
1285 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1286 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1287 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1289 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1290 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1291 pFT_Done_Face(ft_face);
1295 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1296 we don't want to load these. */
1297 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1301 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1303 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1304 pFT_Done_Face(ft_face);
1310 if(!ft_face->family_name || !ft_face->style_name) {
1311 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1312 pFT_Done_Face(ft_face);
1316 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1318 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1319 pFT_Done_Face(ft_face);
1325 localised_family = get_familyname(ft_face);
1326 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1328 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1329 HeapFree(GetProcessHeap(), 0, localised_family);
1330 num_faces = ft_face->num_faces;
1331 pFT_Done_Face(ft_face);
1334 HeapFree(GetProcessHeap(), 0, localised_family);
1338 family_name = ft_face->family_name;
1342 My_FT_Bitmap_Size *size = NULL;
1345 if(!FT_IS_SCALABLE(ft_face))
1346 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1348 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1349 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1350 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1352 localised_family = NULL;
1354 localised_family = get_familyname(ft_face);
1355 if(localised_family && !strcmpiW(localised_family, english_family)) {
1356 HeapFree(GetProcessHeap(), 0, localised_family);
1357 localised_family = NULL;
1362 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1363 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1364 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1369 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1370 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1371 list_init(&family->faces);
1372 list_add_tail(&font_list, &family->entry);
1374 if(localised_family) {
1375 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1376 subst->from.name = strdupW(english_family);
1377 subst->from.charset = -1;
1378 subst->to.name = strdupW(localised_family);
1379 subst->to.charset = -1;
1380 add_font_subst(&font_subst_list, subst, 0);
1383 HeapFree(GetProcessHeap(), 0, localised_family);
1384 HeapFree(GetProcessHeap(), 0, english_family);
1386 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1387 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1388 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1390 internal_leading = 0;
1391 memset(&fs, 0, sizeof(fs));
1393 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1395 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1396 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1397 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1398 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1399 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1400 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1401 if(pOS2->version == 0) {
1404 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1405 fs.fsCsb[0] |= FS_LATIN1;
1407 fs.fsCsb[0] |= FS_SYMBOL;
1410 #ifdef HAVE_FREETYPE_FTWINFNT_H
1411 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1413 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1414 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1415 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1417 internal_leading = winfnt_header.internal_leading;
1421 face_elem_ptr = list_head(&family->faces);
1422 while(face_elem_ptr) {
1423 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1424 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1425 if(!strcmpiW(face->StyleName, StyleW) &&
1426 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1427 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1428 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1429 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1432 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1433 HeapFree(GetProcessHeap(), 0, StyleW);
1434 pFT_Done_Face(ft_face);
1437 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1438 TRACE("Original font is newer so skipping this one\n");
1439 HeapFree(GetProcessHeap(), 0, StyleW);
1440 pFT_Done_Face(ft_face);
1443 TRACE("Replacing original with this one\n");
1444 list_remove(&face->entry);
1445 HeapFree(GetProcessHeap(), 0, face->file);
1446 HeapFree(GetProcessHeap(), 0, face->StyleName);
1447 HeapFree(GetProcessHeap(), 0, face);
1452 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1453 face->cached_enum_data = NULL;
1454 face->StyleName = StyleW;
1457 face->file = strdupA(file);
1458 face->font_data_ptr = NULL;
1459 face->font_data_size = 0;
1464 face->font_data_ptr = font_data_ptr;
1465 face->font_data_size = font_data_size;
1467 face->face_index = face_index;
1469 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1470 face->ntmFlags |= NTM_ITALIC;
1471 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1472 face->ntmFlags |= NTM_BOLD;
1473 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1474 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1475 face->family = family;
1476 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1478 memset(&face->fs_links, 0, sizeof(face->fs_links));
1480 if(FT_IS_SCALABLE(ft_face)) {
1481 memset(&face->size, 0, sizeof(face->size));
1482 face->scalable = TRUE;
1484 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1485 size->height, size->width, size->size >> 6,
1486 size->x_ppem >> 6, size->y_ppem >> 6);
1487 face->size.height = size->height;
1488 face->size.width = size->width;
1489 face->size.size = size->size;
1490 face->size.x_ppem = size->x_ppem;
1491 face->size.y_ppem = size->y_ppem;
1492 face->size.internal_leading = internal_leading;
1493 face->scalable = FALSE;
1496 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1498 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1500 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1501 face->ntmFlags |= NTM_PS_OPENTYPE;
1504 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1505 face->fs.fsCsb[0], face->fs.fsCsb[1],
1506 face->fs.fsUsb[0], face->fs.fsUsb[1],
1507 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1510 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1511 for(i = 0; i < ft_face->num_charmaps; i++) {
1512 switch(ft_face->charmaps[i]->encoding) {
1513 case FT_ENCODING_UNICODE:
1514 case FT_ENCODING_APPLE_ROMAN:
1515 face->fs.fsCsb[0] |= FS_LATIN1;
1517 case FT_ENCODING_MS_SYMBOL:
1518 face->fs.fsCsb[0] |= FS_SYMBOL;
1526 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1527 have_installed_roman_font = TRUE;
1529 AddFaceToFamily(face, family);
1531 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1533 num_faces = ft_face->num_faces;
1534 pFT_Done_Face(ft_face);
1535 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1536 debugstr_w(StyleW));
1537 } while(num_faces > ++face_index);
1541 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1543 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1546 static void DumpFontList(void)
1550 struct list *family_elem_ptr, *face_elem_ptr;
1552 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1553 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1554 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1555 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1556 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1557 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1559 TRACE(" %d", face->size.height);
1566 /***********************************************************
1567 * The replacement list is a way to map an entire font
1568 * family onto another family. For example adding
1570 * [HKCU\Software\Wine\Fonts\Replacements]
1571 * "Wingdings"="Winedings"
1573 * would enumerate the Winedings font both as Winedings and
1574 * Wingdings. However if a real Wingdings font is present the
1575 * replacement does not take place.
1578 static void LoadReplaceList(void)
1581 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1586 struct list *family_elem_ptr, *face_elem_ptr;
1589 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1590 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1592 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1593 &valuelen, &datalen, NULL, NULL);
1595 valuelen++; /* returned value doesn't include room for '\0' */
1596 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1597 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1601 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1602 &dlen) == ERROR_SUCCESS) {
1603 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1604 /* "NewName"="Oldname" */
1605 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1607 /* Find the old family and hence all of the font files
1609 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1610 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1611 if(!strcmpiW(family->FamilyName, data)) {
1612 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1613 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1614 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1615 debugstr_w(face->StyleName), familyA);
1616 /* Now add a new entry with the new family name */
1617 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1622 /* reset dlen and vlen */
1626 HeapFree(GetProcessHeap(), 0, data);
1627 HeapFree(GetProcessHeap(), 0, value);
1632 /*************************************************************
1635 static BOOL init_system_links(void)
1639 DWORD type, max_val, max_data, val_len, data_len, index;
1640 WCHAR *value, *data;
1641 WCHAR *entry, *next;
1642 SYSTEM_LINKS *font_link, *system_font_link;
1643 CHILD_FONT *child_font;
1644 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1645 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1651 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1653 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1654 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1655 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1656 val_len = max_val + 1;
1657 data_len = max_data;
1659 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1661 memset(&fs, 0, sizeof(fs));
1662 psub = get_font_subst(&font_subst_list, value, -1);
1663 /* Don't store fonts that are only substitutes for other fonts */
1666 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1669 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1670 font_link->font_name = strdupW(value);
1671 list_init(&font_link->links);
1672 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1675 CHILD_FONT *child_font;
1677 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1679 next = entry + strlenW(entry) + 1;
1681 face_name = strchrW(entry, ',');
1685 while(isspaceW(*face_name))
1688 psub = get_font_subst(&font_subst_list, face_name, -1);
1690 face_name = psub->to.name;
1692 face = find_face_from_filename(entry, face_name);
1695 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1699 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1700 child_font->face = face;
1701 child_font->font = NULL;
1702 fs.fsCsb[0] |= face->fs.fsCsb[0];
1703 fs.fsCsb[1] |= face->fs.fsCsb[1];
1704 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1705 list_add_tail(&font_link->links, &child_font->entry);
1707 family = find_family_from_name(font_link->font_name);
1710 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1712 face->fs_links = fs;
1715 list_add_tail(&system_links, &font_link->entry);
1717 val_len = max_val + 1;
1718 data_len = max_data;
1721 HeapFree(GetProcessHeap(), 0, value);
1722 HeapFree(GetProcessHeap(), 0, data);
1726 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1729 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1730 system_font_link->font_name = strdupW(System);
1731 list_init(&system_font_link->links);
1733 face = find_face_from_filename(tahoma_ttf, Tahoma);
1736 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1737 child_font->face = face;
1738 child_font->font = NULL;
1739 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1740 list_add_tail(&system_font_link->links, &child_font->entry);
1742 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1744 if(!strcmpiW(font_link->font_name, Tahoma))
1746 CHILD_FONT *font_link_entry;
1747 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1749 CHILD_FONT *new_child;
1750 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1751 new_child->face = font_link_entry->face;
1752 new_child->font = NULL;
1753 list_add_tail(&system_font_link->links, &new_child->entry);
1758 list_add_tail(&system_links, &system_font_link->entry);
1762 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1765 struct dirent *dent;
1766 char path[MAX_PATH];
1768 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1770 dir = opendir(dirname);
1772 WARN("Can't open directory %s\n", debugstr_a(dirname));
1775 while((dent = readdir(dir)) != NULL) {
1776 struct stat statbuf;
1778 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1781 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1783 sprintf(path, "%s/%s", dirname, dent->d_name);
1785 if(stat(path, &statbuf) == -1)
1787 WARN("Can't stat %s\n", debugstr_a(path));
1790 if(S_ISDIR(statbuf.st_mode))
1791 ReadFontDir(path, external_fonts);
1793 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1799 static void load_fontconfig_fonts(void)
1801 #ifdef SONAME_LIBFONTCONFIG
1802 void *fc_handle = NULL;
1811 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1813 TRACE("Wine cannot find the fontconfig library (%s).\n",
1814 SONAME_LIBFONTCONFIG);
1817 #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;}
1818 LOAD_FUNCPTR(FcConfigGetCurrent);
1819 LOAD_FUNCPTR(FcFontList);
1820 LOAD_FUNCPTR(FcFontSetDestroy);
1821 LOAD_FUNCPTR(FcInit);
1822 LOAD_FUNCPTR(FcObjectSetAdd);
1823 LOAD_FUNCPTR(FcObjectSetCreate);
1824 LOAD_FUNCPTR(FcObjectSetDestroy);
1825 LOAD_FUNCPTR(FcPatternCreate);
1826 LOAD_FUNCPTR(FcPatternDestroy);
1827 LOAD_FUNCPTR(FcPatternGetBool);
1828 LOAD_FUNCPTR(FcPatternGetString);
1831 if(!pFcInit()) return;
1833 config = pFcConfigGetCurrent();
1834 pat = pFcPatternCreate();
1835 os = pFcObjectSetCreate();
1836 pFcObjectSetAdd(os, FC_FILE);
1837 pFcObjectSetAdd(os, FC_SCALABLE);
1838 fontset = pFcFontList(config, pat, os);
1839 if(!fontset) return;
1840 for(i = 0; i < fontset->nfont; i++) {
1843 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1845 TRACE("fontconfig: %s\n", file);
1847 /* We're just interested in OT/TT fonts for now, so this hack just
1848 picks up the scalable fonts without extensions .pf[ab] to save time
1849 loading every other font */
1851 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1853 TRACE("not scalable\n");
1857 len = strlen( file );
1858 if(len < 4) continue;
1859 ext = &file[ len - 3 ];
1860 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1861 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1863 pFcFontSetDestroy(fontset);
1864 pFcObjectSetDestroy(os);
1865 pFcPatternDestroy(pat);
1871 static BOOL load_font_from_data_dir(LPCWSTR file)
1874 const char *data_dir = wine_get_data_dir();
1876 if (!data_dir) data_dir = wine_get_build_dir();
1883 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1885 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1887 strcpy(unix_name, data_dir);
1888 strcat(unix_name, "/fonts/");
1890 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1892 EnterCriticalSection( &freetype_cs );
1893 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1894 LeaveCriticalSection( &freetype_cs );
1895 HeapFree(GetProcessHeap(), 0, unix_name);
1900 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1902 static const WCHAR slashW[] = {'\\','\0'};
1904 WCHAR windowsdir[MAX_PATH];
1907 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1908 strcatW(windowsdir, fontsW);
1909 strcatW(windowsdir, slashW);
1910 strcatW(windowsdir, file);
1911 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1912 EnterCriticalSection( &freetype_cs );
1913 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1914 LeaveCriticalSection( &freetype_cs );
1915 HeapFree(GetProcessHeap(), 0, unixname);
1920 static void load_system_fonts(void)
1923 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1924 const WCHAR * const *value;
1926 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1929 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1930 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1931 strcatW(windowsdir, fontsW);
1932 for(value = SystemFontValues; *value; value++) {
1933 dlen = sizeof(data);
1934 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1938 sprintfW(pathW, fmtW, windowsdir, data);
1939 if((unixname = wine_get_unix_file_name(pathW))) {
1940 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1941 HeapFree(GetProcessHeap(), 0, unixname);
1944 load_font_from_data_dir(data);
1951 /*************************************************************
1953 * This adds registry entries for any externally loaded fonts
1954 * (fonts from fontconfig or FontDirs). It also deletes entries
1955 * of no longer existing fonts.
1958 static void update_reg_entries(void)
1960 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1965 struct list *family_elem_ptr, *face_elem_ptr;
1967 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1968 static const WCHAR spaceW[] = {' ', '\0'};
1971 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1972 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1973 ERR("Can't create Windows font reg key\n");
1977 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1978 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1979 ERR("Can't create Windows font reg key\n");
1983 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1984 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1985 ERR("Can't create external font reg key\n");
1989 /* enumerate the fonts and add external ones to the two keys */
1991 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1992 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1993 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1994 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1995 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1996 if(!face->external) continue;
1998 if (!(face->ntmFlags & NTM_REGULAR))
1999 len = len_fam + strlenW(face->StyleName) + 1;
2000 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2001 strcpyW(valueW, family->FamilyName);
2002 if(len != len_fam) {
2003 strcatW(valueW, spaceW);
2004 strcatW(valueW, face->StyleName);
2006 strcatW(valueW, TrueType);
2008 file = wine_get_dos_file_name(face->file);
2010 len = strlenW(file) + 1;
2013 if((path = strrchr(face->file, '/')) == NULL)
2017 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2019 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2020 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2022 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2023 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2024 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2026 HeapFree(GetProcessHeap(), 0, file);
2027 HeapFree(GetProcessHeap(), 0, valueW);
2031 if(external_key) RegCloseKey(external_key);
2032 if(win9x_key) RegCloseKey(win9x_key);
2033 if(winnt_key) RegCloseKey(winnt_key);
2037 static void delete_external_font_keys(void)
2039 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2040 DWORD dlen, vlen, datalen, valuelen, i, type;
2044 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2045 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2046 ERR("Can't create Windows font reg key\n");
2050 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2051 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2052 ERR("Can't create Windows font reg key\n");
2056 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2057 ERR("Can't create external font reg key\n");
2061 /* Delete all external fonts added last time */
2063 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2064 &valuelen, &datalen, NULL, NULL);
2065 valuelen++; /* returned value doesn't include room for '\0' */
2066 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2067 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2069 dlen = datalen * sizeof(WCHAR);
2072 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2073 &dlen) == ERROR_SUCCESS) {
2075 RegDeleteValueW(winnt_key, valueW);
2076 RegDeleteValueW(win9x_key, valueW);
2077 /* reset dlen and vlen */
2081 HeapFree(GetProcessHeap(), 0, data);
2082 HeapFree(GetProcessHeap(), 0, valueW);
2084 /* Delete the old external fonts key */
2085 RegCloseKey(external_key);
2086 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2089 if(win9x_key) RegCloseKey(win9x_key);
2090 if(winnt_key) RegCloseKey(winnt_key);
2093 /*************************************************************
2094 * WineEngAddFontResourceEx
2097 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2103 if (ft_handle) /* do it only if we have freetype up and running */
2108 FIXME("Ignoring flags %x\n", flags);
2110 if((unixname = wine_get_unix_file_name(file)))
2112 EnterCriticalSection( &freetype_cs );
2113 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2114 LeaveCriticalSection( &freetype_cs );
2115 HeapFree(GetProcessHeap(), 0, unixname);
2117 if (!ret && !strchrW(file, '\\')) {
2118 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2119 ret = load_font_from_winfonts_dir(file);
2121 /* Try in datadir/fonts (or builddir/fonts),
2122 * needed for Magic the Gathering Online
2124 ret = load_font_from_data_dir(file);
2131 /*************************************************************
2132 * WineEngAddFontMemResourceEx
2135 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2139 if (ft_handle) /* do it only if we have freetype up and running */
2141 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2143 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2144 memcpy(pFontCopy, pbFont, cbFont);
2146 EnterCriticalSection( &freetype_cs );
2147 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2148 LeaveCriticalSection( &freetype_cs );
2152 TRACE("AddFontToList failed\n");
2153 HeapFree(GetProcessHeap(), 0, pFontCopy);
2156 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2157 * For now return something unique but quite random
2159 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2160 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2167 /*************************************************************
2168 * WineEngRemoveFontResourceEx
2171 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2174 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2178 static const struct nls_update_font_list
2180 UINT ansi_cp, oem_cp;
2181 const char *oem, *fixed, *system;
2182 const char *courier, *serif, *small, *sserif;
2183 /* these are for font substitutes */
2184 const char *shelldlg, *tmsrmn;
2185 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2189 const char *from, *to;
2190 } arial_0, courier_new_0, times_new_roman_0;
2191 } nls_update_font_list[] =
2193 /* Latin 1 (United States) */
2194 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2195 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2196 "Tahoma","Times New Roman",
2197 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2200 /* Latin 1 (Multilingual) */
2201 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2202 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2203 "Tahoma","Times New Roman", /* FIXME unverified */
2204 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2207 /* Eastern Europe */
2208 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2209 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2210 "Tahoma","Times New Roman", /* FIXME unverified */
2211 "Fixedsys,238", "System,238",
2212 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2213 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2214 { "Arial CE,0", "Arial,238" },
2215 { "Courier New CE,0", "Courier New,238" },
2216 { "Times New Roman CE,0", "Times New Roman,238" }
2219 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2220 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2221 "Tahoma","Times New Roman", /* FIXME unverified */
2222 "Fixedsys,204", "System,204",
2223 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2224 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2225 { "Arial Cyr,0", "Arial,204" },
2226 { "Courier New Cyr,0", "Courier New,204" },
2227 { "Times New Roman Cyr,0", "Times New Roman,204" }
2230 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2231 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2232 "Tahoma","Times New Roman", /* FIXME unverified */
2233 "Fixedsys,161", "System,161",
2234 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2235 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2236 { "Arial Greek,0", "Arial,161" },
2237 { "Courier New Greek,0", "Courier New,161" },
2238 { "Times New Roman Greek,0", "Times New Roman,161" }
2241 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2242 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2243 "Tahoma","Times New Roman", /* FIXME unverified */
2244 "Fixedsys,162", "System,162",
2245 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2246 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2247 { "Arial Tur,0", "Arial,162" },
2248 { "Courier New Tur,0", "Courier New,162" },
2249 { "Times New Roman Tur,0", "Times New Roman,162" }
2252 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2253 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2254 "Tahoma","Times New Roman", /* FIXME unverified */
2255 "Fixedsys,177", "System,177",
2256 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2257 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2261 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2262 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2263 "Tahoma","Times New Roman", /* FIXME unverified */
2264 "Fixedsys,178", "System,178",
2265 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2266 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2270 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2271 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2272 "Tahoma","Times New Roman", /* FIXME unverified */
2273 "Fixedsys,186", "System,186",
2274 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2275 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2276 { "Arial Baltic,0", "Arial,186" },
2277 { "Courier New Baltic,0", "Courier New,186" },
2278 { "Times New Roman Baltic,0", "Times New Roman,186" }
2281 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2282 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2283 "Tahoma","Times New Roman", /* FIXME unverified */
2284 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2288 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2289 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2290 "Tahoma","Times New Roman", /* FIXME unverified */
2291 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2295 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2296 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2297 "MS UI Gothic","MS Serif",
2298 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2301 /* Chinese Simplified */
2302 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2303 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2304 "SimSun", "NSimSun",
2305 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2309 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2310 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2312 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2315 /* Chinese Traditional */
2316 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2317 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2318 "PMingLiU", "MingLiU",
2319 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2324 static const WCHAR *font_links_list[] =
2326 Lucida_Sans_Unicode,
2327 Microsoft_Sans_Serif,
2331 static const struct font_links_defaults_list
2333 /* Keyed off substitution for "MS Shell Dlg" */
2334 const WCHAR *shelldlg;
2335 /* Maximum of four substitutes, plus terminating NULL pointer */
2336 const WCHAR *substitutes[5];
2337 } font_links_defaults_list[] =
2339 /* Non East-Asian */
2340 { Tahoma, /* FIXME unverified ordering */
2341 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2343 /* Below lists are courtesy of
2344 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2348 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2350 /* Chinese Simplified */
2352 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2356 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2358 /* Chinese Traditional */
2360 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2364 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2366 return ( ansi_cp == 932 /* CP932 for Japanese */
2367 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2368 || ansi_cp == 949 /* CP949 for Korean */
2369 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2372 static inline HKEY create_fonts_NT_registry_key(void)
2376 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2377 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2381 static inline HKEY create_fonts_9x_registry_key(void)
2385 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2386 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2390 static inline HKEY create_config_fonts_registry_key(void)
2394 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2395 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2399 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2401 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2402 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2403 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2404 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2407 static void set_value_key(HKEY hkey, const char *name, const char *value)
2410 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2412 RegDeleteValueA(hkey, name);
2415 static void update_font_info(void)
2417 char buf[40], cpbuf[40];
2420 UINT i, ansi_cp = 0, oem_cp = 0;
2423 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2426 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2427 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2428 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2429 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2430 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2432 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2433 if (is_dbcs_ansi_cp(ansi_cp))
2434 use_default_fallback = TRUE;
2437 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2439 if (!strcmp( buf, cpbuf )) /* already set correctly */
2444 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2446 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2448 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2451 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2455 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2456 nls_update_font_list[i].oem_cp == oem_cp)
2458 hkey = create_config_fonts_registry_key();
2459 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2460 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2461 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2464 hkey = create_fonts_NT_registry_key();
2465 add_font_list(hkey, &nls_update_font_list[i]);
2468 hkey = create_fonts_9x_registry_key();
2469 add_font_list(hkey, &nls_update_font_list[i]);
2472 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2474 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2475 strlen(nls_update_font_list[i].shelldlg)+1);
2476 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2477 strlen(nls_update_font_list[i].tmsrmn)+1);
2479 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2480 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2481 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2482 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2483 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2484 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2485 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2486 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2488 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2489 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2490 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2498 /* Delete the FontSubstitutes from other locales */
2499 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2501 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2502 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2503 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2509 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2511 /* Clear out system links */
2512 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2515 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2525 WCHAR buff[MAX_PATH];
2529 static const WCHAR comma[] = {',',0};
2531 RegDeleteValueW(hkey, name);
2536 for (i = 0; values[i] != NULL; i++)
2539 if (!strcmpiW(name,value))
2541 psub = get_font_subst(&font_subst_list, value, -1);
2543 value = psub->to.name;
2544 family = find_family_from_name(value);
2548 /* Use first extant filename for this Family */
2549 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2553 file = strrchr(face->file, '/');
2562 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2563 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2564 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2565 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2566 if (sizeof(buff)-(data-buff) < entryLen + 1)
2568 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2569 HeapFree(GetProcessHeap(), 0, fileW);
2572 strcpyW(data, fileW);
2573 strcatW(data, comma);
2574 strcatW(data, value);
2576 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2577 HeapFree(GetProcessHeap(), 0, fileW);
2583 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2585 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2587 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2590 static void update_system_links(void)
2598 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2600 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2602 if (disposition == REG_OPENED_EXISTING_KEY)
2604 TRACE("SystemLink key already exists, doing nothing\n");
2609 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2611 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2616 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2618 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2620 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2621 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2623 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2624 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2627 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2629 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2634 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2636 WARN("failed to create SystemLink key\n");
2640 static BOOL init_freetype(void)
2642 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2645 "Wine cannot find the FreeType font library. To enable Wine to\n"
2646 "use TrueType fonts please install a version of FreeType greater than\n"
2647 "or equal to 2.0.5.\n"
2648 "http://www.freetype.org\n");
2652 #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;}
2654 LOAD_FUNCPTR(FT_Vector_Unit)
2655 LOAD_FUNCPTR(FT_Done_Face)
2656 LOAD_FUNCPTR(FT_Get_Char_Index)
2657 LOAD_FUNCPTR(FT_Get_Module)
2658 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2659 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2660 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2661 LOAD_FUNCPTR(FT_Init_FreeType)
2662 LOAD_FUNCPTR(FT_Load_Glyph)
2663 LOAD_FUNCPTR(FT_Matrix_Multiply)
2664 #ifndef FT_MULFIX_INLINED
2665 LOAD_FUNCPTR(FT_MulFix)
2667 LOAD_FUNCPTR(FT_New_Face)
2668 LOAD_FUNCPTR(FT_New_Memory_Face)
2669 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2670 LOAD_FUNCPTR(FT_Outline_Transform)
2671 LOAD_FUNCPTR(FT_Outline_Translate)
2672 LOAD_FUNCPTR(FT_Select_Charmap)
2673 LOAD_FUNCPTR(FT_Set_Charmap)
2674 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2675 LOAD_FUNCPTR(FT_Vector_Transform)
2676 LOAD_FUNCPTR(FT_Render_Glyph)
2679 /* Don't warn if these ones are missing */
2680 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2681 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2682 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2683 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2684 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2685 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2686 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2688 #ifdef HAVE_FREETYPE_FTWINFNT_H
2689 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2691 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2692 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2693 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2694 <= 2.0.3 has FT_Sqrt64 */
2698 if(pFT_Init_FreeType(&library) != 0) {
2699 ERR("Can't init FreeType library\n");
2700 wine_dlclose(ft_handle, NULL, 0);
2704 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2705 if (pFT_Library_Version)
2706 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2708 if (FT_Version.major<=0)
2714 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2715 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2716 ((FT_Version.minor << 8) & 0x00ff00) |
2717 ((FT_Version.patch ) & 0x0000ff);
2723 "Wine cannot find certain functions that it needs inside the FreeType\n"
2724 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2725 "FreeType to at least version 2.0.5.\n"
2726 "http://www.freetype.org\n");
2727 wine_dlclose(ft_handle, NULL, 0);
2732 /*************************************************************
2735 * Initialize FreeType library and create a list of available faces
2737 BOOL WineEngInit(void)
2739 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2740 static const WCHAR pathW[] = {'P','a','t','h',0};
2742 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2743 WCHAR windowsdir[MAX_PATH];
2746 const char *data_dir;
2750 /* update locale dependent font info in registry */
2753 if(!init_freetype()) return FALSE;
2755 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2756 ERR("Failed to create font mutex\n");
2759 WaitForSingleObject(font_mutex, INFINITE);
2761 delete_external_font_keys();
2763 /* load the system bitmap fonts */
2764 load_system_fonts();
2766 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2767 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2768 strcatW(windowsdir, fontsW);
2769 if((unixname = wine_get_unix_file_name(windowsdir)))
2771 ReadFontDir(unixname, FALSE);
2772 HeapFree(GetProcessHeap(), 0, unixname);
2775 /* load the system truetype fonts */
2776 data_dir = wine_get_data_dir();
2777 if (!data_dir) data_dir = wine_get_build_dir();
2778 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2779 strcpy(unixname, data_dir);
2780 strcat(unixname, "/fonts/");
2781 ReadFontDir(unixname, TRUE);
2782 HeapFree(GetProcessHeap(), 0, unixname);
2785 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2786 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2787 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2789 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2790 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2791 &hkey) == ERROR_SUCCESS) {
2792 LPWSTR data, valueW;
2793 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2794 &valuelen, &datalen, NULL, NULL);
2796 valuelen++; /* returned value doesn't include room for '\0' */
2797 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2798 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2801 dlen = datalen * sizeof(WCHAR);
2803 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2804 &dlen) == ERROR_SUCCESS) {
2805 if(data[0] && (data[1] == ':'))
2807 if((unixname = wine_get_unix_file_name(data)))
2809 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2810 HeapFree(GetProcessHeap(), 0, unixname);
2813 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2815 WCHAR pathW[MAX_PATH];
2816 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2819 sprintfW(pathW, fmtW, windowsdir, data);
2820 if((unixname = wine_get_unix_file_name(pathW)))
2822 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2823 HeapFree(GetProcessHeap(), 0, unixname);
2826 load_font_from_data_dir(data);
2828 /* reset dlen and vlen */
2833 HeapFree(GetProcessHeap(), 0, data);
2834 HeapFree(GetProcessHeap(), 0, valueW);
2838 load_fontconfig_fonts();
2840 /* then look in any directories that we've specified in the config file */
2841 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2842 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2848 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2850 len += sizeof(WCHAR);
2851 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2852 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2854 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2855 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2856 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2857 TRACE( "got font path %s\n", debugstr_a(valueA) );
2861 LPSTR next = strchr( ptr, ':' );
2862 if (next) *next++ = 0;
2863 ReadFontDir( ptr, TRUE );
2866 HeapFree( GetProcessHeap(), 0, valueA );
2868 HeapFree( GetProcessHeap(), 0, valueW );
2877 update_reg_entries();
2879 update_system_links();
2880 init_system_links();
2882 ReleaseMutex(font_mutex);
2887 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2890 TT_HoriHeader *pHori;
2894 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2895 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2897 if(height == 0) height = 16;
2899 /* Calc. height of EM square:
2901 * For +ve lfHeight we have
2902 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2903 * Re-arranging gives:
2904 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2906 * For -ve lfHeight we have
2908 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2909 * with il = winAscent + winDescent - units_per_em]
2914 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2915 ppem = MulDiv(ft_face->units_per_EM, height,
2916 pHori->Ascender - pHori->Descender);
2918 ppem = MulDiv(ft_face->units_per_EM, height,
2919 pOS2->usWinAscent + pOS2->usWinDescent);
2927 static struct font_mapping *map_font_file( const char *name )
2929 struct font_mapping *mapping;
2933 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2934 if (fstat( fd, &st ) == -1) goto error;
2936 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2938 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2940 mapping->refcount++;
2945 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2948 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2951 if (mapping->data == MAP_FAILED)
2953 HeapFree( GetProcessHeap(), 0, mapping );
2956 mapping->refcount = 1;
2957 mapping->dev = st.st_dev;
2958 mapping->ino = st.st_ino;
2959 mapping->size = st.st_size;
2960 list_add_tail( &mappings_list, &mapping->entry );
2968 static void unmap_font_file( struct font_mapping *mapping )
2970 if (!--mapping->refcount)
2972 list_remove( &mapping->entry );
2973 munmap( mapping->data, mapping->size );
2974 HeapFree( GetProcessHeap(), 0, mapping );
2978 static LONG load_VDMX(GdiFont*, LONG);
2980 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2987 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2991 if (!(font->mapping = map_font_file( face->file )))
2993 WARN("failed to map %s\n", debugstr_a(face->file));
2996 data_ptr = font->mapping->data;
2997 data_size = font->mapping->size;
3001 data_ptr = face->font_data_ptr;
3002 data_size = face->font_data_size;
3005 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3007 ERR("FT_New_Face rets %d\n", err);
3011 /* set it here, as load_VDMX needs it */
3012 font->ft_face = ft_face;
3014 if(FT_IS_SCALABLE(ft_face)) {
3015 /* load the VDMX table if we have one */
3016 font->ppem = load_VDMX(font, height);
3018 font->ppem = calc_ppem_for_height(ft_face, height);
3019 TRACE("height %d => ppem %d\n", height, font->ppem);
3021 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3022 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3024 font->ppem = height;
3025 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3026 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3032 static int get_nearest_charset(Face *face, int *cp)
3034 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3035 a single face with the requested charset. The idea is to check if
3036 the selected font supports the current ANSI codepage, if it does
3037 return the corresponding charset, else return the first charset */
3040 int acp = GetACP(), i;
3044 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3045 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3046 return csi.ciCharset;
3048 for(i = 0; i < 32; i++) {
3050 if(face->fs.fsCsb[0] & fs0) {
3051 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3053 return csi.ciCharset;
3056 FIXME("TCI failing on %x\n", fs0);
3060 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3061 face->fs.fsCsb[0], face->file);
3063 return DEFAULT_CHARSET;
3066 static GdiFont *alloc_font(void)
3068 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3070 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3071 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3073 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3074 ret->total_kern_pairs = (DWORD)-1;
3075 ret->kern_pairs = NULL;
3076 list_init(&ret->hfontlist);
3077 list_init(&ret->child_fonts);
3081 static void free_font(GdiFont *font)
3083 struct list *cursor, *cursor2;
3086 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3088 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3089 list_remove(cursor);
3091 free_font(child->font);
3092 HeapFree(GetProcessHeap(), 0, child);
3095 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3097 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3098 DeleteObject(hfontlist->hfont);
3099 list_remove(&hfontlist->entry);
3100 HeapFree(GetProcessHeap(), 0, hfontlist);
3103 if (font->ft_face) pFT_Done_Face(font->ft_face);
3104 if (font->mapping) unmap_font_file( font->mapping );
3105 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3106 HeapFree(GetProcessHeap(), 0, font->potm);
3107 HeapFree(GetProcessHeap(), 0, font->name);
3108 for (i = 0; i < font->gmsize; i++)
3109 HeapFree(GetProcessHeap(),0,font->gm[i]);
3110 HeapFree(GetProcessHeap(), 0, font->gm);
3111 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3112 HeapFree(GetProcessHeap(), 0, font);
3116 /*************************************************************
3119 * load the vdmx entry for the specified height
3122 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3123 ( ( (FT_ULong)_x4 << 24 ) | \
3124 ( (FT_ULong)_x3 << 16 ) | \
3125 ( (FT_ULong)_x2 << 8 ) | \
3128 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3143 static LONG load_VDMX(GdiFont *font, LONG height)
3147 BYTE devXRatio, devYRatio;
3148 USHORT numRecs, numRatios;
3149 DWORD result, offset = -1;
3153 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3155 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3158 /* FIXME: need the real device aspect ratio */
3162 numRecs = GET_BE_WORD(hdr[1]);
3163 numRatios = GET_BE_WORD(hdr[2]);
3165 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3166 for(i = 0; i < numRatios; i++) {
3169 offset = (3 * 2) + (i * sizeof(Ratios));
3170 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3173 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3175 if((ratio.xRatio == 0 &&
3176 ratio.yStartRatio == 0 &&
3177 ratio.yEndRatio == 0) ||
3178 (devXRatio == ratio.xRatio &&
3179 devYRatio >= ratio.yStartRatio &&
3180 devYRatio <= ratio.yEndRatio))
3182 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3183 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3184 offset = GET_BE_WORD(tmp);
3190 FIXME("No suitable ratio found\n");
3194 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3196 BYTE startsz, endsz;
3199 recs = GET_BE_WORD(group.recs);
3200 startsz = group.startsz;
3201 endsz = group.endsz;
3203 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3205 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3206 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3207 if(result == GDI_ERROR) {
3208 FIXME("Failed to retrieve vTable\n");
3213 for(i = 0; i < recs; i++) {
3214 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3215 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3216 ppem = GET_BE_WORD(vTable[i * 3]);
3218 if(yMax + -yMin == height) {
3221 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3224 if(yMax + -yMin > height) {
3227 goto end; /* failed */
3229 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3230 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3231 ppem = GET_BE_WORD(vTable[i * 3]);
3232 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3238 TRACE("ppem not found for height %d\n", height);
3242 HeapFree(GetProcessHeap(), 0, vTable);
3248 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3250 if(font->font_desc.hash != fd->hash) return TRUE;
3251 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3252 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3253 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3254 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3257 static void calc_hash(FONT_DESC *pfd)
3259 DWORD hash = 0, *ptr, two_chars;
3263 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3265 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3267 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3269 pwc = (WCHAR *)&two_chars;
3271 *pwc = toupperW(*pwc);
3273 *pwc = toupperW(*pwc);
3277 hash ^= !pfd->can_use_bitmap;
3282 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3287 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3291 fd.can_use_bitmap = can_use_bitmap;
3294 /* try the child list */
3295 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3296 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3297 if(!fontcmp(ret, &fd)) {
3298 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3299 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3300 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3301 if(hflist->hfont == hfont)
3307 /* try the in-use list */
3308 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3309 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3310 if(!fontcmp(ret, &fd)) {
3311 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3312 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3313 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3314 if(hflist->hfont == hfont)
3317 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3318 hflist->hfont = hfont;
3319 list_add_head(&ret->hfontlist, &hflist->entry);
3324 /* then the unused list */
3325 font_elem_ptr = list_head(&unused_gdi_font_list);
3326 while(font_elem_ptr) {
3327 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3328 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3329 if(!fontcmp(ret, &fd)) {
3330 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3331 assert(list_empty(&ret->hfontlist));
3332 TRACE("Found %p in unused list\n", ret);
3333 list_remove(&ret->entry);
3334 list_add_head(&gdi_font_list, &ret->entry);
3335 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3336 hflist->hfont = hfont;
3337 list_add_head(&ret->hfontlist, &hflist->entry);
3344 static void add_to_cache(GdiFont *font)
3346 static DWORD cache_num = 1;
3348 font->cache_num = cache_num++;
3349 list_add_head(&gdi_font_list, &font->entry);
3352 /*************************************************************
3353 * create_child_font_list
3355 static BOOL create_child_font_list(GdiFont *font)
3358 SYSTEM_LINKS *font_link;
3359 CHILD_FONT *font_link_entry, *new_child;
3363 psub = get_font_subst(&font_subst_list, font->name, -1);
3364 font_name = psub ? psub->to.name : font->name;
3365 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3367 if(!strcmpiW(font_link->font_name, font_name))
3369 TRACE("found entry in system list\n");
3370 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3372 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3373 new_child->face = font_link_entry->face;
3374 new_child->font = NULL;
3375 list_add_tail(&font->child_fonts, &new_child->entry);
3376 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3383 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3384 * Sans Serif. This is how asian windows get default fallbacks for fonts
3386 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3387 font->charset != OEM_CHARSET &&
3388 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3389 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3391 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3393 TRACE("found entry in default fallback list\n");
3394 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3396 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3397 new_child->face = font_link_entry->face;
3398 new_child->font = NULL;
3399 list_add_tail(&font->child_fonts, &new_child->entry);
3400 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3410 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3412 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3414 if (pFT_Set_Charmap)
3417 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3419 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3421 for (i = 0; i < ft_face->num_charmaps; i++)
3423 if (ft_face->charmaps[i]->encoding == encoding)
3425 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3426 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3428 switch (ft_face->charmaps[i]->platform_id)
3431 cmap_def = ft_face->charmaps[i];
3433 case 0: /* Apple Unicode */
3434 cmap0 = ft_face->charmaps[i];
3436 case 1: /* Macintosh */
3437 cmap1 = ft_face->charmaps[i];
3440 cmap2 = ft_face->charmaps[i];
3442 case 3: /* Microsoft */
3443 cmap3 = ft_face->charmaps[i];
3448 if (cmap3) /* prefer Microsoft cmap table */
3449 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3451 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3453 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3455 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3457 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3459 return ft_err == FT_Err_Ok;
3462 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3465 /*************************************************************
3466 * WineEngCreateFontInstance
3469 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3472 Face *face, *best, *best_bitmap;
3473 Family *family, *last_resort_family;
3474 struct list *family_elem_ptr, *face_elem_ptr;
3475 INT height, width = 0;
3476 unsigned int score = 0, new_score;
3477 signed int diff = 0, newdiff;
3478 BOOL bd, it, can_use_bitmap;
3483 FontSubst *psub = NULL;
3485 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3486 lf.lfWidth = abs(lf.lfWidth);
3488 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3490 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3491 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3492 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3495 if(dc->GraphicsMode == GM_ADVANCED)
3496 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3499 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3500 font scaling abilities. */
3501 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3502 dcmat.eM21 = dcmat.eM12 = 0;
3505 /* Try to avoid not necessary glyph transformations */
3506 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3508 lf.lfHeight *= fabs(dcmat.eM11);
3509 lf.lfWidth *= fabs(dcmat.eM11);
3510 dcmat.eM11 = dcmat.eM22 = 1.0;
3513 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3514 dcmat.eM21, dcmat.eM22);
3517 EnterCriticalSection( &freetype_cs );
3519 /* check the cache first */
3520 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3521 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3522 LeaveCriticalSection( &freetype_cs );
3526 TRACE("not in cache\n");
3527 if(list_empty(&font_list)) /* No fonts installed */
3529 TRACE("No fonts installed\n");
3530 LeaveCriticalSection( &freetype_cs );
3533 if(!have_installed_roman_font)
3535 TRACE("No roman font installed\n");
3536 LeaveCriticalSection( &freetype_cs );
3542 ret->font_desc.matrix = dcmat;
3543 ret->font_desc.lf = lf;
3544 ret->font_desc.can_use_bitmap = can_use_bitmap;
3545 calc_hash(&ret->font_desc);
3546 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3547 hflist->hfont = hfont;
3548 list_add_head(&ret->hfontlist, &hflist->entry);
3550 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3551 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3552 original value lfCharSet. Note this is a special case for
3553 Symbol and doesn't happen at least for "Wingdings*" */
3555 if(!strcmpiW(lf.lfFaceName, SymbolW))
3556 lf.lfCharSet = SYMBOL_CHARSET;
3558 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3559 switch(lf.lfCharSet) {
3560 case DEFAULT_CHARSET:
3561 csi.fs.fsCsb[0] = 0;
3564 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3565 csi.fs.fsCsb[0] = 0;
3571 if(lf.lfFaceName[0] != '\0') {
3572 SYSTEM_LINKS *font_link;
3573 CHILD_FONT *font_link_entry;
3574 LPWSTR FaceName = lf.lfFaceName;
3577 * Check for a leading '@' this signals that the font is being
3578 * requested in tategaki mode (vertical writing substitution) but
3579 * does not affect the fontface that is to be selected.
3581 if (lf.lfFaceName[0]=='@')
3582 FaceName = &lf.lfFaceName[1];
3584 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3587 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3588 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3589 if (psub->to.charset != -1)
3590 lf.lfCharSet = psub->to.charset;
3593 /* We want a match on name and charset or just name if
3594 charset was DEFAULT_CHARSET. If the latter then
3595 we fixup the returned charset later in get_nearest_charset
3596 where we'll either use the charset of the current ansi codepage
3597 or if that's unavailable the first charset that the font supports.
3599 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3600 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3601 if (!strcmpiW(family->FamilyName, FaceName) ||
3602 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3604 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3605 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3606 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3607 if(face->scalable || can_use_bitmap)
3614 * Try check the SystemLink list first for a replacement font.
3615 * We may find good replacements there.
3617 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3619 if(!strcmpiW(font_link->font_name, FaceName) ||
3620 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3622 TRACE("found entry in system list\n");
3623 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3625 face = font_link_entry->face;
3626 family = face->family;
3627 if(csi.fs.fsCsb[0] &
3628 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3630 if(face->scalable || can_use_bitmap)
3638 psub = NULL; /* substitution is no more relevant */
3640 /* If requested charset was DEFAULT_CHARSET then try using charset
3641 corresponding to the current ansi codepage */
3642 if (!csi.fs.fsCsb[0])
3645 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3646 FIXME("TCI failed on codepage %d\n", acp);
3647 csi.fs.fsCsb[0] = 0;
3649 lf.lfCharSet = csi.ciCharset;
3652 /* Face families are in the top 4 bits of lfPitchAndFamily,
3653 so mask with 0xF0 before testing */
3655 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3656 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3657 strcpyW(lf.lfFaceName, defFixed);
3658 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3659 strcpyW(lf.lfFaceName, defSerif);
3660 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3661 strcpyW(lf.lfFaceName, defSans);
3663 strcpyW(lf.lfFaceName, defSans);
3664 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3665 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3666 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3667 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3668 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3669 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3670 if(face->scalable || can_use_bitmap)
3676 last_resort_family = NULL;
3677 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3678 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3679 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3680 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3681 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3684 if(can_use_bitmap && !last_resort_family)
3685 last_resort_family = family;
3690 if(last_resort_family) {
3691 family = last_resort_family;
3692 csi.fs.fsCsb[0] = 0;
3696 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3697 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3698 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3699 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3700 if(face->scalable) {
3701 csi.fs.fsCsb[0] = 0;
3702 WARN("just using first face for now\n");
3705 if(can_use_bitmap && !last_resort_family)
3706 last_resort_family = family;
3709 if(!last_resort_family) {
3710 FIXME("can't find a single appropriate font - bailing\n");
3712 LeaveCriticalSection( &freetype_cs );
3716 WARN("could only find a bitmap font - this will probably look awful!\n");
3717 family = last_resort_family;
3718 csi.fs.fsCsb[0] = 0;
3721 it = lf.lfItalic ? 1 : 0;
3722 bd = lf.lfWeight > 550 ? 1 : 0;
3724 height = lf.lfHeight;
3726 face = best = best_bitmap = NULL;
3727 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3729 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3733 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3734 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3735 new_score = (italic ^ it) + (bold ^ bd);
3736 if(!best || new_score <= score)
3738 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3739 italic, bold, it, bd);
3742 if(best->scalable && score == 0) break;
3746 newdiff = height - (signed int)(best->size.height);
3748 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3749 if(!best_bitmap || new_score < score ||
3750 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3752 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3755 if(score == 0 && diff == 0) break;
3762 face = best->scalable ? best : best_bitmap;
3763 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3764 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3768 if(csi.fs.fsCsb[0]) {
3769 ret->charset = lf.lfCharSet;
3770 ret->codepage = csi.ciACP;
3773 ret->charset = get_nearest_charset(face, &ret->codepage);
3775 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3776 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3778 ret->aveWidth = height ? lf.lfWidth : 0;
3780 if(!face->scalable) {
3781 /* Windows uses integer scaling factors for bitmap fonts */
3782 INT scale, scaled_height;
3783 GdiFont *cachedfont;
3785 /* FIXME: rotation of bitmap fonts is ignored */
3786 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3788 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3789 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3790 dcmat.eM11 = dcmat.eM22 = 1.0;
3791 /* As we changed the matrix, we need to search the cache for the font again,
3792 * otherwise we might explode the cache. */
3793 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3794 TRACE("Found cached font after non-scalable matrix rescale!\n");
3796 LeaveCriticalSection( &freetype_cs );
3799 calc_hash(&ret->font_desc);
3801 if (height != 0) height = diff;
3802 height += face->size.height;
3804 scale = (height + face->size.height - 1) / face->size.height;
3805 scaled_height = scale * face->size.height;
3806 /* Only jump to the next height if the difference <= 25% original height */
3807 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3808 /* The jump between unscaled and doubled is delayed by 1 */
3809 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3810 ret->scale_y = scale;
3812 width = face->size.x_ppem >> 6;
3813 height = face->size.y_ppem >> 6;
3817 TRACE("font scale y: %f\n", ret->scale_y);
3819 ret->ft_face = OpenFontFace(ret, face, width, height);
3824 LeaveCriticalSection( &freetype_cs );
3828 ret->ntmFlags = face->ntmFlags;
3830 if (ret->charset == SYMBOL_CHARSET &&
3831 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3834 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3838 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3841 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3842 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3843 ret->underline = lf.lfUnderline ? 0xff : 0;
3844 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3845 create_child_font_list(ret);
3847 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3849 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3850 if (length != GDI_ERROR)
3852 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3853 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3854 TRACE("Loaded GSUB table of %i bytes\n",length);
3858 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3861 LeaveCriticalSection( &freetype_cs );
3865 static void dump_gdi_font_list(void)
3868 struct list *elem_ptr;
3870 TRACE("---------- gdiFont Cache ----------\n");
3871 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3872 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3873 TRACE("gdiFont=%p %s %d\n",
3874 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3877 TRACE("---------- Unused gdiFont Cache ----------\n");
3878 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3879 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3880 TRACE("gdiFont=%p %s %d\n",
3881 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3884 TRACE("---------- Child gdiFont Cache ----------\n");
3885 LIST_FOR_EACH(elem_ptr, &child_font_list) {
3886 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3887 TRACE("gdiFont=%p %s %d\n",
3888 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3892 /*************************************************************
3893 * WineEngDestroyFontInstance
3895 * free the gdiFont associated with this handle
3898 BOOL WineEngDestroyFontInstance(HFONT handle)
3903 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3907 EnterCriticalSection( &freetype_cs );
3909 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3911 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3912 while(hfontlist_elem_ptr) {
3913 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3914 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3915 if(hflist->hfont == handle) {
3916 TRACE("removing child font %p from child list\n", gdiFont);
3917 list_remove(&gdiFont->entry);
3918 LeaveCriticalSection( &freetype_cs );
3924 TRACE("destroying hfont=%p\n", handle);
3926 dump_gdi_font_list();
3928 font_elem_ptr = list_head(&gdi_font_list);
3929 while(font_elem_ptr) {
3930 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3931 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3933 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3934 while(hfontlist_elem_ptr) {
3935 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3936 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3937 if(hflist->hfont == handle) {
3938 list_remove(&hflist->entry);
3939 HeapFree(GetProcessHeap(), 0, hflist);
3943 if(list_empty(&gdiFont->hfontlist)) {
3944 TRACE("Moving to Unused list\n");
3945 list_remove(&gdiFont->entry);
3946 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3951 font_elem_ptr = list_head(&unused_gdi_font_list);
3952 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3953 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3954 while(font_elem_ptr) {
3955 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3956 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3957 TRACE("freeing %p\n", gdiFont);
3958 list_remove(&gdiFont->entry);
3961 LeaveCriticalSection( &freetype_cs );
3965 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3966 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3971 if (face->cached_enum_data)
3974 *pelf = face->cached_enum_data->elf;
3975 *pntm = face->cached_enum_data->ntm;
3976 *ptype = face->cached_enum_data->type;
3980 font = alloc_font();
3982 if(face->scalable) {
3983 height = -2048; /* 2048 is the most common em size */
3986 height = face->size.y_ppem >> 6;
3987 width = face->size.x_ppem >> 6;
3989 font->scale_y = 1.0;
3991 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3997 font->name = strdupW(face->family->FamilyName);
3998 font->ntmFlags = face->ntmFlags;
4000 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4002 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4004 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4006 lstrcpynW(pelf->elfLogFont.lfFaceName,
4007 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4009 lstrcpynW(pelf->elfFullName,
4010 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4012 lstrcpynW(pelf->elfStyle,
4013 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4018 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4020 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4022 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4023 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4024 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4027 pntm->ntmTm.ntmFlags = face->ntmFlags;
4028 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4029 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4030 pntm->ntmFontSig = face->fs;
4032 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4034 pelf->elfLogFont.lfEscapement = 0;
4035 pelf->elfLogFont.lfOrientation = 0;
4036 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4037 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4038 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4039 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4040 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4041 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4042 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4043 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4044 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4045 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4046 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4049 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4050 *ptype |= TRUETYPE_FONTTYPE;
4051 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4052 *ptype |= DEVICE_FONTTYPE;
4053 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4054 *ptype |= RASTER_FONTTYPE;
4056 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4057 if (face->cached_enum_data)
4059 face->cached_enum_data->elf = *pelf;
4060 face->cached_enum_data->ntm = *pntm;
4061 face->cached_enum_data->type = *ptype;
4067 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4069 struct list *face_elem_ptr;
4071 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4073 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4075 static const WCHAR spaceW[] = { ' ',0 };
4076 WCHAR full_family_name[LF_FULLFACESIZE];
4077 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4079 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4081 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4082 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4086 strcpyW(full_family_name, family->FamilyName);
4087 strcatW(full_family_name, spaceW);
4088 strcatW(full_family_name, face->StyleName);
4089 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4095 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4097 static const WCHAR spaceW[] = { ' ',0 };
4098 WCHAR full_family_name[LF_FULLFACESIZE];
4100 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4102 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4104 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4105 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4109 strcpyW(full_family_name, face->family->FamilyName);
4110 strcatW(full_family_name, spaceW);
4111 strcatW(full_family_name, face->StyleName);
4112 return !strcmpiW(lf->lfFaceName, full_family_name);
4115 /*************************************************************
4119 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4123 struct list *family_elem_ptr, *face_elem_ptr;
4125 NEWTEXTMETRICEXW ntm;
4134 lf.lfCharSet = DEFAULT_CHARSET;
4135 lf.lfPitchAndFamily = 0;
4136 lf.lfFaceName[0] = 0;
4140 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4143 EnterCriticalSection( &freetype_cs );
4144 if(plf->lfFaceName[0]) {
4146 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4149 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4150 debugstr_w(psub->to.name));
4152 strcpyW(lf.lfFaceName, psub->to.name);
4156 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4157 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4158 if(family_matches(family, plf)) {
4159 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4160 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4162 if (!face_matches(face, plf)) continue;
4164 GetEnumStructs(face, &elf, &ntm, &type);
4165 for(i = 0; i < 32; i++) {
4166 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4167 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4168 strcpyW(elf.elfScript, OEM_DOSW);
4169 i = 32; /* break out of loop */
4170 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4173 fs.fsCsb[0] = 1L << i;
4175 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4177 csi.ciCharset = DEFAULT_CHARSET;
4178 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4179 if(csi.ciCharset != DEFAULT_CHARSET) {
4180 elf.elfLogFont.lfCharSet =
4181 ntm.ntmTm.tmCharSet = csi.ciCharset;
4183 strcpyW(elf.elfScript, ElfScriptsW[i]);
4185 FIXME("Unknown elfscript for bit %d\n", i);
4188 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
4189 debugstr_w(elf.elfLogFont.lfFaceName),
4190 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4191 csi.ciCharset, type, debugstr_w(elf.elfScript),
4192 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4193 ntm.ntmTm.ntmFlags);
4194 /* release section before callback (FIXME) */
4195 LeaveCriticalSection( &freetype_cs );
4196 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4197 EnterCriticalSection( &freetype_cs );
4203 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4204 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4205 face_elem_ptr = list_head(&family->faces);
4206 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4207 GetEnumStructs(face, &elf, &ntm, &type);
4208 for(i = 0; i < 32; i++) {
4209 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4210 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4211 strcpyW(elf.elfScript, OEM_DOSW);
4212 i = 32; /* break out of loop */
4213 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4216 fs.fsCsb[0] = 1L << i;
4218 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4220 csi.ciCharset = DEFAULT_CHARSET;
4221 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4222 if(csi.ciCharset != DEFAULT_CHARSET) {
4223 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
4226 strcpyW(elf.elfScript, ElfScriptsW[i]);
4228 FIXME("Unknown elfscript for bit %d\n", i);
4231 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4232 debugstr_w(elf.elfLogFont.lfFaceName),
4233 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4234 csi.ciCharset, type, debugstr_w(elf.elfScript),
4235 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4236 ntm.ntmTm.ntmFlags);
4237 /* release section before callback (FIXME) */
4238 LeaveCriticalSection( &freetype_cs );
4239 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4240 EnterCriticalSection( &freetype_cs );
4244 LeaveCriticalSection( &freetype_cs );
4248 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4250 pt->x.value = vec->x >> 6;
4251 pt->x.fract = (vec->x & 0x3f) << 10;
4252 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4253 pt->y.value = vec->y >> 6;
4254 pt->y.fract = (vec->y & 0x3f) << 10;
4255 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4259 /***************************************************
4260 * According to the MSDN documentation on WideCharToMultiByte,
4261 * certain codepages cannot set the default_used parameter.
4262 * This returns TRUE if the codepage can set that parameter, false else
4263 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4265 static BOOL codepage_sets_default_used(UINT codepage)
4279 * GSUB Table handling functions
4282 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4284 const GSUB_CoverageFormat1* cf1;
4288 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4290 int count = GET_BE_WORD(cf1->GlyphCount);
4292 TRACE("Coverage Format 1, %i glyphs\n",count);
4293 for (i = 0; i < count; i++)
4294 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4298 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4300 const GSUB_CoverageFormat2* cf2;
4303 cf2 = (const GSUB_CoverageFormat2*)cf1;
4305 count = GET_BE_WORD(cf2->RangeCount);
4306 TRACE("Coverage Format 2, %i ranges\n",count);
4307 for (i = 0; i < count; i++)
4309 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4311 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4312 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4314 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4315 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4321 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4326 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4328 const GSUB_ScriptList *script;
4329 const GSUB_Script *deflt = NULL;
4331 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4333 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4334 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4336 const GSUB_Script *scr;
4339 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4340 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4342 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4344 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4350 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4354 const GSUB_LangSys *Lang;
4356 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4358 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4360 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4361 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4363 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4366 offset = GET_BE_WORD(script->DefaultLangSys);
4369 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4375 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4378 const GSUB_FeatureList *feature;
4379 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4381 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4382 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4384 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4385 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4387 const GSUB_Feature *feat;
4388 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4395 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4399 const GSUB_LookupList *lookup;
4400 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4402 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4403 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4405 const GSUB_LookupTable *look;
4406 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4407 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4408 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4409 if (GET_BE_WORD(look->LookupType) != 1)
4410 FIXME("We only handle SubType 1\n");
4415 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4417 const GSUB_SingleSubstFormat1 *ssf1;
4418 offset = GET_BE_WORD(look->SubTable[j]);
4419 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4420 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4422 int offset = GET_BE_WORD(ssf1->Coverage);
4423 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4424 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4426 TRACE(" Glyph 0x%x ->",glyph);
4427 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4428 TRACE(" 0x%x\n",glyph);
4433 const GSUB_SingleSubstFormat2 *ssf2;
4437 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4438 offset = GET_BE_WORD(ssf1->Coverage);
4439 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4440 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4441 TRACE(" Coverage index %i\n",index);
4444 TRACE(" Glyph is 0x%x ->",glyph);
4445 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4446 TRACE("0x%x\n",glyph);
4455 static const char* get_opentype_script(const GdiFont *font)
4458 * I am not sure if this is the correct way to generate our script tag
4461 switch (font->charset)
4463 case ANSI_CHARSET: return "latn";
4464 case BALTIC_CHARSET: return "latn"; /* ?? */
4465 case CHINESEBIG5_CHARSET: return "hani";
4466 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4467 case GB2312_CHARSET: return "hani";
4468 case GREEK_CHARSET: return "grek";
4469 case HANGUL_CHARSET: return "hang";
4470 case RUSSIAN_CHARSET: return "cyrl";
4471 case SHIFTJIS_CHARSET: return "kana";
4472 case TURKISH_CHARSET: return "latn"; /* ?? */
4473 case VIETNAMESE_CHARSET: return "latn";
4474 case JOHAB_CHARSET: return "latn"; /* ?? */
4475 case ARABIC_CHARSET: return "arab";
4476 case HEBREW_CHARSET: return "hebr";
4477 case THAI_CHARSET: return "thai";
4478 default: return "latn";
4482 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4484 const GSUB_Header *header;
4485 const GSUB_Script *script;
4486 const GSUB_LangSys *language;
4487 const GSUB_Feature *feature;
4489 if (!font->GSUB_Table)
4492 header = font->GSUB_Table;
4494 script = GSUB_get_script_table(header, get_opentype_script(font));
4497 TRACE("Script not found\n");
4500 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4503 TRACE("Language not found\n");
4506 feature = GSUB_get_feature(header, language, "vrt2");
4508 feature = GSUB_get_feature(header, language, "vert");
4511 TRACE("vrt2/vert feature not found\n");
4514 return GSUB_apply_feature(header, feature, glyph);
4517 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4521 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4522 WCHAR wc = (WCHAR)glyph;
4524 BOOL *default_used_pointer;
4527 default_used_pointer = NULL;
4528 default_used = FALSE;
4529 if (codepage_sets_default_used(font->codepage))
4530 default_used_pointer = &default_used;
4531 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4534 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4535 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4536 return get_GSUB_vert_glyph(font,ret);
4539 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4540 glyph = glyph + 0xf000;
4541 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4542 return get_GSUB_vert_glyph(font,glyphId);
4545 /*************************************************************
4546 * WineEngGetGlyphIndices
4549 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4550 LPWORD pgi, DWORD flags)
4553 int default_char = -1;
4555 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4557 for(i = 0; i < count; i++)
4559 pgi[i] = get_glyph_index(font, lpstr[i]);
4562 if (default_char == -1)
4564 if (FT_IS_SFNT(font->ft_face))
4566 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4567 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4572 WineEngGetTextMetrics(font, &textm);
4573 default_char = textm.tmDefaultChar;
4576 pgi[i] = default_char;
4582 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4584 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4585 return !memcmp(matrix, &identity, sizeof(FMAT2));
4588 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4590 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4591 return !memcmp(matrix, &identity, sizeof(MAT2));
4594 /*************************************************************
4595 * WineEngGetGlyphOutline
4597 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4598 * except that the first parameter is the HWINEENGFONT of the font in
4599 * question rather than an HDC.
4602 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4603 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4606 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4607 FT_Face ft_face = incoming_font->ft_face;
4608 GdiFont *font = incoming_font;
4609 FT_UInt glyph_index;
4610 DWORD width, height, pitch, needed = 0;
4611 FT_Bitmap ft_bitmap;
4613 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4615 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4616 double widthRatio = 1.0;
4617 FT_Matrix transMat = identityMat;
4618 FT_Matrix transMatUnrotated;
4619 BOOL needsTransform = FALSE;
4620 BOOL tategaki = (font->GSUB_Table != NULL);
4621 UINT original_index;
4623 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4624 buflen, buf, lpmat);
4626 TRACE("font transform %f %f %f %f\n",
4627 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4628 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4631 EnterCriticalSection( &freetype_cs );
4633 if(format & GGO_GLYPH_INDEX) {
4634 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4635 original_index = glyph;
4636 format &= ~GGO_GLYPH_INDEX;
4638 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4639 ft_face = font->ft_face;
4640 original_index = glyph_index;
4643 if(format & GGO_UNHINTED) {
4644 load_flags |= FT_LOAD_NO_HINTING;
4645 format &= ~GGO_UNHINTED;
4648 /* tategaki never appears to happen to lower glyph index */
4649 if (glyph_index < TATEGAKI_LOWER_BOUND )
4652 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4653 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4654 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4655 font->gmsize * sizeof(GM*));
4657 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4658 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4660 *lpgm = FONT_GM(font,original_index)->gm;
4661 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4662 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4663 lpgm->gmCellIncX, lpgm->gmCellIncY);
4664 LeaveCriticalSection( &freetype_cs );
4665 return 1; /* FIXME */
4669 if (!font->gm[original_index / GM_BLOCK_SIZE])
4670 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4672 /* Scaling factor */
4677 WineEngGetTextMetrics(font, &tm);
4679 widthRatio = (double)font->aveWidth;
4680 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4683 widthRatio = font->scale_y;
4685 /* Scaling transform */
4686 if (widthRatio != 1.0 || font->scale_y != 1.0)
4689 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4692 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4694 pFT_Matrix_Multiply(&scaleMat, &transMat);
4695 needsTransform = TRUE;
4698 /* Slant transform */
4699 if (font->fake_italic) {
4702 slantMat.xx = (1 << 16);
4703 slantMat.xy = ((1 << 16) >> 2);
4705 slantMat.yy = (1 << 16);
4706 pFT_Matrix_Multiply(&slantMat, &transMat);
4707 needsTransform = TRUE;
4710 /* Rotation transform */
4711 transMatUnrotated = transMat;
4712 if(font->orientation && !tategaki) {
4713 FT_Matrix rotationMat;
4715 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4716 pFT_Vector_Unit(&vecAngle, angle);
4717 rotationMat.xx = vecAngle.x;
4718 rotationMat.xy = -vecAngle.y;
4719 rotationMat.yx = -rotationMat.xy;
4720 rotationMat.yy = rotationMat.xx;
4722 pFT_Matrix_Multiply(&rotationMat, &transMat);
4723 needsTransform = TRUE;
4726 /* World transform */
4727 if (!is_identity_FMAT2(&font->font_desc.matrix))
4730 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4731 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4732 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4733 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4734 pFT_Matrix_Multiply(&worldMat, &transMat);
4735 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4736 needsTransform = TRUE;
4739 /* Extra transformation specified by caller */
4740 if (!is_identity_MAT2(lpmat))
4743 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4744 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4745 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4746 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4747 pFT_Matrix_Multiply(&extraMat, &transMat);
4748 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4749 needsTransform = TRUE;
4752 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4753 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4754 format == GGO_GRAY8_BITMAP))
4756 load_flags |= FT_LOAD_NO_BITMAP;
4759 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4762 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4763 LeaveCriticalSection( &freetype_cs );
4767 if(!needsTransform) {
4768 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4769 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4770 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4772 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4773 bottom = (ft_face->glyph->metrics.horiBearingY -
4774 ft_face->glyph->metrics.height) & -64;
4775 lpgm->gmCellIncX = adv;
4776 lpgm->gmCellIncY = 0;
4783 for(xc = 0; xc < 2; xc++) {
4784 for(yc = 0; yc < 2; yc++) {
4785 vec.x = (ft_face->glyph->metrics.horiBearingX +
4786 xc * ft_face->glyph->metrics.width);
4787 vec.y = ft_face->glyph->metrics.horiBearingY -
4788 yc * ft_face->glyph->metrics.height;
4789 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4790 pFT_Vector_Transform(&vec, &transMat);
4791 if(xc == 0 && yc == 0) {
4792 left = right = vec.x;
4793 top = bottom = vec.y;
4795 if(vec.x < left) left = vec.x;
4796 else if(vec.x > right) right = vec.x;
4797 if(vec.y < bottom) bottom = vec.y;
4798 else if(vec.y > top) top = vec.y;
4803 right = (right + 63) & -64;
4804 bottom = bottom & -64;
4805 top = (top + 63) & -64;
4807 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4808 vec.x = ft_face->glyph->metrics.horiAdvance;
4810 pFT_Vector_Transform(&vec, &transMat);
4811 lpgm->gmCellIncX = (vec.x+63) >> 6;
4812 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4814 vec.x = ft_face->glyph->metrics.horiAdvance;
4816 pFT_Vector_Transform(&vec, &transMatUnrotated);
4817 adv = (vec.x+63) >> 6;
4821 bbx = (right - left) >> 6;
4822 lpgm->gmBlackBoxX = (right - left) >> 6;
4823 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4824 lpgm->gmptGlyphOrigin.x = left >> 6;
4825 lpgm->gmptGlyphOrigin.y = top >> 6;
4827 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4828 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4829 lpgm->gmCellIncX, lpgm->gmCellIncY);
4831 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4832 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4834 FONT_GM(font,original_index)->gm = *lpgm;
4835 FONT_GM(font,original_index)->adv = adv;
4836 FONT_GM(font,original_index)->lsb = lsb;
4837 FONT_GM(font,original_index)->bbx = bbx;
4838 FONT_GM(font,original_index)->init = TRUE;
4841 if(format == GGO_METRICS)
4843 LeaveCriticalSection( &freetype_cs );
4844 return 1; /* FIXME */
4847 if(ft_face->glyph->format != ft_glyph_format_outline &&
4848 (format == GGO_NATIVE || format == GGO_BEZIER ||
4849 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4850 format == GGO_GRAY8_BITMAP))
4852 TRACE("loaded a bitmap\n");
4853 LeaveCriticalSection( &freetype_cs );
4859 width = lpgm->gmBlackBoxX;
4860 height = lpgm->gmBlackBoxY;
4861 pitch = ((width + 31) >> 5) << 2;
4862 needed = pitch * height;
4864 if(!buf || !buflen) break;
4866 switch(ft_face->glyph->format) {
4867 case ft_glyph_format_bitmap:
4869 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4870 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4871 INT h = ft_face->glyph->bitmap.rows;
4873 memcpy(dst, src, w);
4874 src += ft_face->glyph->bitmap.pitch;
4880 case ft_glyph_format_outline:
4881 ft_bitmap.width = width;
4882 ft_bitmap.rows = height;
4883 ft_bitmap.pitch = pitch;
4884 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4885 ft_bitmap.buffer = buf;
4888 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4890 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4892 /* Note: FreeType will only set 'black' bits for us. */
4893 memset(buf, 0, needed);
4894 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4898 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4899 LeaveCriticalSection( &freetype_cs );
4904 case GGO_GRAY2_BITMAP:
4905 case GGO_GRAY4_BITMAP:
4906 case GGO_GRAY8_BITMAP:
4907 case WINE_GGO_GRAY16_BITMAP:
4909 unsigned int mult, row, col;
4912 width = lpgm->gmBlackBoxX;
4913 height = lpgm->gmBlackBoxY;
4914 pitch = (width + 3) / 4 * 4;
4915 needed = pitch * height;
4917 if(!buf || !buflen) break;
4919 switch(ft_face->glyph->format) {
4920 case ft_glyph_format_bitmap:
4922 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4923 INT h = ft_face->glyph->bitmap.rows;
4926 for(x = 0; x < pitch; x++)
4928 if(x < ft_face->glyph->bitmap.width)
4929 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4933 src += ft_face->glyph->bitmap.pitch;
4936 LeaveCriticalSection( &freetype_cs );
4939 case ft_glyph_format_outline:
4941 ft_bitmap.width = width;
4942 ft_bitmap.rows = height;
4943 ft_bitmap.pitch = pitch;
4944 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4945 ft_bitmap.buffer = buf;
4948 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4950 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4952 memset(ft_bitmap.buffer, 0, buflen);
4954 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4956 if(format == GGO_GRAY2_BITMAP)
4958 else if(format == GGO_GRAY4_BITMAP)
4960 else if(format == GGO_GRAY8_BITMAP)
4962 else /* format == WINE_GGO_GRAY16_BITMAP */
4964 LeaveCriticalSection( &freetype_cs );
4970 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4971 LeaveCriticalSection( &freetype_cs );
4976 for(row = 0; row < height; row++) {
4978 for(col = 0; col < width; col++, ptr++) {
4979 *ptr = (((int)*ptr) * mult + 128) / 256;
4986 case WINE_GGO_HRGB_BITMAP:
4987 case WINE_GGO_HBGR_BITMAP:
4988 case WINE_GGO_VRGB_BITMAP:
4989 case WINE_GGO_VBGR_BITMAP:
4990 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4992 switch (ft_face->glyph->format)
4994 case FT_GLYPH_FORMAT_BITMAP:
4999 width = lpgm->gmBlackBoxX;
5000 height = lpgm->gmBlackBoxY;
5002 needed = pitch * height;
5004 if (!buf || !buflen) break;
5006 memset(buf, 0, buflen);
5008 src = ft_face->glyph->bitmap.buffer;
5009 src_pitch = ft_face->glyph->bitmap.pitch;
5013 for (x = 0; x < width; x++)
5015 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5016 ((unsigned int *)dst)[x] = ~0u;
5025 case FT_GLYPH_FORMAT_OUTLINE:
5029 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5030 INT x_shift, y_shift;
5032 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5033 FT_Render_Mode render_mode =
5034 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5035 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5037 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5039 if ( render_mode == FT_RENDER_MODE_LCD)
5041 lpgm->gmBlackBoxX += 2;
5042 lpgm->gmptGlyphOrigin.x -= 1;
5046 lpgm->gmBlackBoxY += 2;
5047 lpgm->gmptGlyphOrigin.y += 1;
5051 width = lpgm->gmBlackBoxX;
5052 height = lpgm->gmBlackBoxY;
5054 needed = pitch * height;
5056 if (!buf || !buflen) break;
5058 memset(buf, 0, buflen);
5060 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5062 if ( needsTransform )
5063 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5065 if ( pFT_Library_SetLcdFilter )
5066 pFT_Library_SetLcdFilter( library, lcdfilter );
5067 pFT_Render_Glyph (ft_face->glyph, render_mode);
5069 src = ft_face->glyph->bitmap.buffer;
5070 src_pitch = ft_face->glyph->bitmap.pitch;
5071 src_width = ft_face->glyph->bitmap.width;
5072 src_height = ft_face->glyph->bitmap.rows;
5074 if ( render_mode == FT_RENDER_MODE_LCD)
5082 rgb_interval = src_pitch;
5087 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5088 if ( x_shift < 0 ) x_shift = 0;
5089 if ( x_shift + (src_width / hmul) > width )
5090 x_shift = width - (src_width / hmul);
5092 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5093 if ( y_shift < 0 ) y_shift = 0;
5094 if ( y_shift + (src_height / vmul) > height )
5095 y_shift = height - (src_height / vmul);
5097 dst += x_shift + y_shift * ( pitch / 4 );
5098 while ( src_height )
5100 for ( x = 0; x < src_width / hmul; x++ )
5104 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5105 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5106 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5107 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5111 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5112 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5113 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5114 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5117 src += src_pitch * vmul;
5126 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5127 LeaveCriticalSection ( &freetype_cs );
5134 LeaveCriticalSection( &freetype_cs );
5140 int contour, point = 0, first_pt;
5141 FT_Outline *outline = &ft_face->glyph->outline;
5142 TTPOLYGONHEADER *pph;
5144 DWORD pph_start, cpfx, type;
5146 if(buflen == 0) buf = NULL;
5148 if (needsTransform && buf) {
5149 pFT_Outline_Transform(outline, &transMat);
5152 for(contour = 0; contour < outline->n_contours; contour++) {
5154 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5157 pph->dwType = TT_POLYGON_TYPE;
5158 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5160 needed += sizeof(*pph);
5162 while(point <= outline->contours[contour]) {
5163 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5164 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5165 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5169 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5172 } while(point <= outline->contours[contour] &&
5173 (outline->tags[point] & FT_Curve_Tag_On) ==
5174 (outline->tags[point-1] & FT_Curve_Tag_On));
5175 /* At the end of a contour Windows adds the start point, but
5177 if(point > outline->contours[contour] &&
5178 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5180 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5182 } else if(point <= outline->contours[contour] &&
5183 outline->tags[point] & FT_Curve_Tag_On) {
5184 /* add closing pt for bezier */
5186 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5194 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5197 pph->cb = needed - pph_start;
5203 /* Convert the quadratic Beziers to cubic Beziers.
5204 The parametric eqn for a cubic Bezier is, from PLRM:
5205 r(t) = at^3 + bt^2 + ct + r0
5206 with the control points:
5211 A quadratic Beizer has the form:
5212 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5214 So equating powers of t leads to:
5215 r1 = 2/3 p1 + 1/3 p0
5216 r2 = 2/3 p1 + 1/3 p2
5217 and of course r0 = p0, r3 = p2
5220 int contour, point = 0, first_pt;
5221 FT_Outline *outline = &ft_face->glyph->outline;
5222 TTPOLYGONHEADER *pph;
5224 DWORD pph_start, cpfx, type;
5225 FT_Vector cubic_control[4];
5226 if(buflen == 0) buf = NULL;
5228 if (needsTransform && buf) {
5229 pFT_Outline_Transform(outline, &transMat);
5232 for(contour = 0; contour < outline->n_contours; contour++) {
5234 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5237 pph->dwType = TT_POLYGON_TYPE;
5238 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5240 needed += sizeof(*pph);
5242 while(point <= outline->contours[contour]) {
5243 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5244 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5245 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5248 if(type == TT_PRIM_LINE) {
5250 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5254 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5257 /* FIXME: Possible optimization in endpoint calculation
5258 if there are two consecutive curves */
5259 cubic_control[0] = outline->points[point-1];
5260 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5261 cubic_control[0].x += outline->points[point].x + 1;
5262 cubic_control[0].y += outline->points[point].y + 1;
5263 cubic_control[0].x >>= 1;
5264 cubic_control[0].y >>= 1;
5266 if(point+1 > outline->contours[contour])
5267 cubic_control[3] = outline->points[first_pt];
5269 cubic_control[3] = outline->points[point+1];
5270 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5271 cubic_control[3].x += outline->points[point].x + 1;
5272 cubic_control[3].y += outline->points[point].y + 1;
5273 cubic_control[3].x >>= 1;
5274 cubic_control[3].y >>= 1;
5277 /* r1 = 1/3 p0 + 2/3 p1
5278 r2 = 1/3 p2 + 2/3 p1 */
5279 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5280 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5281 cubic_control[2] = cubic_control[1];
5282 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5283 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5284 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5285 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5287 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5288 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5289 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5294 } while(point <= outline->contours[contour] &&
5295 (outline->tags[point] & FT_Curve_Tag_On) ==
5296 (outline->tags[point-1] & FT_Curve_Tag_On));
5297 /* At the end of a contour Windows adds the start point,
5298 but only for Beziers and we've already done that.
5300 if(point <= outline->contours[contour] &&
5301 outline->tags[point] & FT_Curve_Tag_On) {
5302 /* This is the closing pt of a bezier, but we've already
5303 added it, so just inc point and carry on */
5310 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5313 pph->cb = needed - pph_start;
5319 FIXME("Unsupported format %d\n", format);
5320 LeaveCriticalSection( &freetype_cs );
5323 LeaveCriticalSection( &freetype_cs );
5327 static BOOL get_bitmap_text_metrics(GdiFont *font)
5329 FT_Face ft_face = font->ft_face;
5330 #ifdef HAVE_FREETYPE_FTWINFNT_H
5331 FT_WinFNT_HeaderRec winfnt_header;
5333 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5334 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5335 font->potm->otmSize = size;
5337 #define TM font->potm->otmTextMetrics
5338 #ifdef HAVE_FREETYPE_FTWINFNT_H
5339 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5341 TM.tmHeight = winfnt_header.pixel_height;
5342 TM.tmAscent = winfnt_header.ascent;
5343 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5344 TM.tmInternalLeading = winfnt_header.internal_leading;
5345 TM.tmExternalLeading = winfnt_header.external_leading;
5346 TM.tmAveCharWidth = winfnt_header.avg_width;
5347 TM.tmMaxCharWidth = winfnt_header.max_width;
5348 TM.tmWeight = winfnt_header.weight;
5350 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5351 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5352 TM.tmFirstChar = winfnt_header.first_char;
5353 TM.tmLastChar = winfnt_header.last_char;
5354 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5355 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5356 TM.tmItalic = winfnt_header.italic;
5357 TM.tmUnderlined = font->underline;
5358 TM.tmStruckOut = font->strikeout;
5359 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5360 TM.tmCharSet = winfnt_header.charset;
5365 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5366 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5367 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5368 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5369 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5370 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5371 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5372 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5374 TM.tmDigitizedAspectX = 96; /* FIXME */
5375 TM.tmDigitizedAspectY = 96; /* FIXME */
5377 TM.tmLastChar = 255;
5378 TM.tmDefaultChar = 32;
5379 TM.tmBreakChar = 32;
5380 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5381 TM.tmUnderlined = font->underline;
5382 TM.tmStruckOut = font->strikeout;
5383 /* NB inverted meaning of TMPF_FIXED_PITCH */
5384 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5385 TM.tmCharSet = font->charset;
5393 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5395 double scale_x, scale_y;
5399 scale_x = (double)font->aveWidth;
5400 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5403 scale_x = font->scale_y;
5405 scale_x *= fabs(font->font_desc.matrix.eM11);
5406 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5408 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5409 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5411 SCALE_Y(ptm->tmHeight);
5412 SCALE_Y(ptm->tmAscent);
5413 SCALE_Y(ptm->tmDescent);
5414 SCALE_Y(ptm->tmInternalLeading);
5415 SCALE_Y(ptm->tmExternalLeading);
5416 SCALE_Y(ptm->tmOverhang);
5418 SCALE_X(ptm->tmAveCharWidth);
5419 SCALE_X(ptm->tmMaxCharWidth);
5425 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5427 double scale_x, scale_y;
5431 scale_x = (double)font->aveWidth;
5432 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5435 scale_x = font->scale_y;
5437 scale_x *= fabs(font->font_desc.matrix.eM11);
5438 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5440 scale_font_metrics(font, &potm->otmTextMetrics);
5442 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5443 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5445 SCALE_Y(potm->otmAscent);
5446 SCALE_Y(potm->otmDescent);
5447 SCALE_Y(potm->otmLineGap);
5448 SCALE_Y(potm->otmsCapEmHeight);
5449 SCALE_Y(potm->otmsXHeight);
5450 SCALE_Y(potm->otmrcFontBox.top);
5451 SCALE_Y(potm->otmrcFontBox.bottom);
5452 SCALE_X(potm->otmrcFontBox.left);
5453 SCALE_X(potm->otmrcFontBox.right);
5454 SCALE_Y(potm->otmMacAscent);
5455 SCALE_Y(potm->otmMacDescent);
5456 SCALE_Y(potm->otmMacLineGap);
5457 SCALE_X(potm->otmptSubscriptSize.x);
5458 SCALE_Y(potm->otmptSubscriptSize.y);
5459 SCALE_X(potm->otmptSubscriptOffset.x);
5460 SCALE_Y(potm->otmptSubscriptOffset.y);
5461 SCALE_X(potm->otmptSuperscriptSize.x);
5462 SCALE_Y(potm->otmptSuperscriptSize.y);
5463 SCALE_X(potm->otmptSuperscriptOffset.x);
5464 SCALE_Y(potm->otmptSuperscriptOffset.y);
5465 SCALE_Y(potm->otmsStrikeoutSize);
5466 SCALE_Y(potm->otmsStrikeoutPosition);
5467 SCALE_Y(potm->otmsUnderscoreSize);
5468 SCALE_Y(potm->otmsUnderscorePosition);
5474 /*************************************************************
5475 * WineEngGetTextMetrics
5478 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5481 EnterCriticalSection( &freetype_cs );
5483 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5484 if(!get_bitmap_text_metrics(font))
5486 LeaveCriticalSection( &freetype_cs );
5490 /* Make sure that the font has sane width/height ratio */
5493 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5495 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5501 *ptm = font->potm->otmTextMetrics;
5502 scale_font_metrics(font, ptm);
5503 LeaveCriticalSection( &freetype_cs );
5507 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5511 for(i = 0; i < ft_face->num_charmaps; i++)
5513 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5519 /*************************************************************
5520 * WineEngGetOutlineTextMetrics
5523 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5524 OUTLINETEXTMETRICW *potm)
5526 FT_Face ft_face = font->ft_face;
5527 UINT needed, lenfam, lensty, ret;
5529 TT_HoriHeader *pHori;
5530 TT_Postscript *pPost;
5531 FT_Fixed x_scale, y_scale;
5532 WCHAR *family_nameW, *style_nameW;
5533 static const WCHAR spaceW[] = {' ', '\0'};
5535 INT ascent, descent;
5537 TRACE("font=%p\n", font);
5539 if(!FT_IS_SCALABLE(ft_face))
5543 EnterCriticalSection( &freetype_cs );
5546 if(cbSize >= font->potm->otmSize)
5548 memcpy(potm, font->potm, font->potm->otmSize);
5549 scale_outline_font_metrics(font, potm);
5551 LeaveCriticalSection( &freetype_cs );
5552 return font->potm->otmSize;
5556 needed = sizeof(*potm);
5558 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5559 family_nameW = strdupW(font->name);
5561 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5563 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5564 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5565 style_nameW, lensty/sizeof(WCHAR));
5567 /* These names should be read from the TT name table */
5569 /* length of otmpFamilyName */
5572 /* length of otmpFaceName */
5573 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5574 needed += lenfam; /* just the family name */
5576 needed += lenfam + lensty; /* family + " " + style */
5579 /* length of otmpStyleName */
5582 /* length of otmpFullName */
5583 needed += lenfam + lensty;
5586 x_scale = ft_face->size->metrics.x_scale;
5587 y_scale = ft_face->size->metrics.y_scale;
5589 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5591 FIXME("Can't find OS/2 table - not TT font?\n");
5596 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5598 FIXME("Can't find HHEA table - not TT font?\n");
5603 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5605 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",
5606 pOS2->usWinAscent, pOS2->usWinDescent,
5607 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5608 ft_face->ascender, ft_face->descender, ft_face->height,
5609 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5610 ft_face->bbox.yMax, ft_face->bbox.yMin);
5612 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5613 font->potm->otmSize = needed;
5615 #define TM font->potm->otmTextMetrics
5617 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5618 ascent = pHori->Ascender;
5619 descent = -pHori->Descender;
5621 ascent = pOS2->usWinAscent;
5622 descent = pOS2->usWinDescent;
5626 TM.tmAscent = font->yMax;
5627 TM.tmDescent = -font->yMin;
5628 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5630 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5631 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5632 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5633 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5636 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5639 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5641 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5642 ((ascent + descent) -
5643 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5645 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5646 if (TM.tmAveCharWidth == 0) {
5647 TM.tmAveCharWidth = 1;
5649 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5650 TM.tmWeight = FW_REGULAR;
5651 if (font->fake_bold)
5652 TM.tmWeight = FW_BOLD;
5655 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5657 if (pOS2->usWeightClass > FW_MEDIUM)
5658 TM.tmWeight = pOS2->usWeightClass;
5660 else if (pOS2->usWeightClass <= FW_MEDIUM)
5661 TM.tmWeight = pOS2->usWeightClass;
5664 TM.tmDigitizedAspectX = 300;
5665 TM.tmDigitizedAspectY = 300;
5666 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5667 * symbol range to 0 - f0ff
5670 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5675 case 1257: /* Baltic */
5676 TM.tmLastChar = 0xf8fd;
5679 TM.tmLastChar = 0xf0ff;
5681 TM.tmBreakChar = 0x20;
5682 TM.tmDefaultChar = 0x1f;
5686 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5687 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5689 if(pOS2->usFirstCharIndex <= 1)
5690 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5691 else if (pOS2->usFirstCharIndex > 0xff)
5692 TM.tmBreakChar = 0x20;
5694 TM.tmBreakChar = pOS2->usFirstCharIndex;
5695 TM.tmDefaultChar = TM.tmBreakChar - 1;
5697 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5698 TM.tmUnderlined = font->underline;
5699 TM.tmStruckOut = font->strikeout;
5701 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5702 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5703 (pOS2->version == 0xFFFFU ||
5704 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5705 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5707 TM.tmPitchAndFamily = 0;
5709 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5711 case PAN_FAMILY_SCRIPT:
5712 TM.tmPitchAndFamily |= FF_SCRIPT;
5715 case PAN_FAMILY_DECORATIVE:
5716 TM.tmPitchAndFamily |= FF_DECORATIVE;
5721 case PAN_FAMILY_TEXT_DISPLAY:
5722 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5723 /* which is clearly not what the panose spec says. */
5725 if(TM.tmPitchAndFamily == 0 || /* fixed */
5726 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5727 TM.tmPitchAndFamily = FF_MODERN;
5730 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5735 TM.tmPitchAndFamily |= FF_DONTCARE;
5738 case PAN_SERIF_COVE:
5739 case PAN_SERIF_OBTUSE_COVE:
5740 case PAN_SERIF_SQUARE_COVE:
5741 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5742 case PAN_SERIF_SQUARE:
5743 case PAN_SERIF_THIN:
5744 case PAN_SERIF_BONE:
5745 case PAN_SERIF_EXAGGERATED:
5746 case PAN_SERIF_TRIANGLE:
5747 TM.tmPitchAndFamily |= FF_ROMAN;
5750 case PAN_SERIF_NORMAL_SANS:
5751 case PAN_SERIF_OBTUSE_SANS:
5752 case PAN_SERIF_PERP_SANS:
5753 case PAN_SERIF_FLARED:
5754 case PAN_SERIF_ROUNDED:
5755 TM.tmPitchAndFamily |= FF_SWISS;
5762 if(FT_IS_SCALABLE(ft_face))
5763 TM.tmPitchAndFamily |= TMPF_VECTOR;
5765 if(FT_IS_SFNT(ft_face))
5767 if (font->ntmFlags & NTM_PS_OPENTYPE)
5768 TM.tmPitchAndFamily |= TMPF_DEVICE;
5770 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5773 TM.tmCharSet = font->charset;
5775 font->potm->otmFiller = 0;
5776 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5777 font->potm->otmfsSelection = pOS2->fsSelection;
5778 font->potm->otmfsType = pOS2->fsType;
5779 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5780 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5781 font->potm->otmItalicAngle = 0; /* POST table */
5782 font->potm->otmEMSquare = ft_face->units_per_EM;
5783 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5784 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5785 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5786 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5787 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5788 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5789 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5790 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5791 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5792 font->potm->otmMacAscent = TM.tmAscent;
5793 font->potm->otmMacDescent = -TM.tmDescent;
5794 font->potm->otmMacLineGap = font->potm->otmLineGap;
5795 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5796 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5797 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5798 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5799 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5800 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5801 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5802 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5803 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5804 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5805 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5807 font->potm->otmsUnderscoreSize = 0;
5808 font->potm->otmsUnderscorePosition = 0;
5810 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5811 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5815 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5816 cp = (char*)font->potm + sizeof(*font->potm);
5817 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5818 strcpyW((WCHAR*)cp, family_nameW);
5820 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5821 strcpyW((WCHAR*)cp, style_nameW);
5823 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5824 strcpyW((WCHAR*)cp, family_nameW);
5825 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5826 strcatW((WCHAR*)cp, spaceW);
5827 strcatW((WCHAR*)cp, style_nameW);
5828 cp += lenfam + lensty;
5831 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5832 strcpyW((WCHAR*)cp, family_nameW);
5833 strcatW((WCHAR*)cp, spaceW);
5834 strcatW((WCHAR*)cp, style_nameW);
5837 if(potm && needed <= cbSize)
5839 memcpy(potm, font->potm, font->potm->otmSize);
5840 scale_outline_font_metrics(font, potm);
5844 HeapFree(GetProcessHeap(), 0, style_nameW);
5845 HeapFree(GetProcessHeap(), 0, family_nameW);
5847 LeaveCriticalSection( &freetype_cs );
5851 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5853 HFONTLIST *hfontlist;
5854 child->font = alloc_font();
5855 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5856 if(!child->font->ft_face)
5858 free_font(child->font);
5863 child->font->font_desc = font->font_desc;
5864 child->font->ntmFlags = child->face->ntmFlags;
5865 child->font->orientation = font->orientation;
5866 child->font->scale_y = font->scale_y;
5867 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5868 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5869 child->font->name = strdupW(child->face->family->FamilyName);
5870 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5871 child->font->base_font = font;
5872 list_add_head(&child_font_list, &child->font->entry);
5873 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5877 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5880 CHILD_FONT *child_font;
5883 font = font->base_font;
5885 *linked_font = font;
5887 if((*glyph = get_glyph_index(font, c)))
5890 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5892 if(!child_font->font)
5893 if(!load_child_font(font, child_font))
5896 if(!child_font->font->ft_face)
5898 g = get_glyph_index(child_font->font, c);
5902 *linked_font = child_font->font;
5909 /*************************************************************
5910 * WineEngGetCharWidth
5913 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5916 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5919 FT_UInt glyph_index;
5920 GdiFont *linked_font;
5922 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5925 EnterCriticalSection( &freetype_cs );
5926 for(c = firstChar; c <= lastChar; c++) {
5927 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5928 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5929 &gm, 0, NULL, &identity);
5930 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5932 LeaveCriticalSection( &freetype_cs );
5936 /*************************************************************
5937 * WineEngGetCharABCWidths
5940 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5943 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5946 FT_UInt glyph_index;
5947 GdiFont *linked_font;
5949 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5951 if(!FT_IS_SCALABLE(font->ft_face))
5955 EnterCriticalSection( &freetype_cs );
5957 for(c = firstChar; c <= lastChar; c++) {
5958 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5959 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5960 &gm, 0, NULL, &identity);
5961 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5962 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5963 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5964 FONT_GM(linked_font,glyph_index)->bbx;
5966 LeaveCriticalSection( &freetype_cs );
5970 /*************************************************************
5971 * WineEngGetCharABCWidthsFloat
5974 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
5976 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
5979 FT_UInt glyph_index;
5980 GdiFont *linked_font;
5982 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
5985 EnterCriticalSection( &freetype_cs );
5987 for (c = first; c <= last; c++)
5989 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5990 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5991 &gm, 0, NULL, &identity);
5992 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
5993 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
5994 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
5995 FONT_GM(linked_font, glyph_index)->lsb -
5996 FONT_GM(linked_font, glyph_index)->bbx;
5998 LeaveCriticalSection( &freetype_cs );
6002 /*************************************************************
6003 * WineEngGetCharABCWidthsI
6006 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6009 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6012 FT_UInt glyph_index;
6013 GdiFont *linked_font;
6015 if(!FT_HAS_HORIZONTAL(font->ft_face))
6019 EnterCriticalSection( &freetype_cs );
6021 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6023 for(c = firstChar; c < firstChar+count; c++) {
6024 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6025 &gm, 0, NULL, &identity);
6026 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6027 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6028 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6029 - FONT_GM(linked_font,c)->bbx;
6032 for(c = 0; c < count; c++) {
6033 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6034 &gm, 0, NULL, &identity);
6035 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6036 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6037 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6038 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6041 LeaveCriticalSection( &freetype_cs );
6045 /*************************************************************
6046 * WineEngGetTextExtentExPoint
6049 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6050 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6052 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6057 FT_UInt glyph_index;
6058 GdiFont *linked_font;
6060 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6064 EnterCriticalSection( &freetype_cs );
6067 WineEngGetTextMetrics(font, &tm);
6068 size->cy = tm.tmHeight;
6070 for(idx = 0; idx < count; idx++) {
6071 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6072 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6073 &gm, 0, NULL, &identity);
6074 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6076 if (! pnfit || ext <= max_ext) {
6086 LeaveCriticalSection( &freetype_cs );
6087 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6091 /*************************************************************
6092 * WineEngGetTextExtentExPointI
6095 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6096 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6098 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6104 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6107 EnterCriticalSection( &freetype_cs );
6110 WineEngGetTextMetrics(font, &tm);
6111 size->cy = tm.tmHeight;
6113 for(idx = 0; idx < count; idx++) {
6114 WineEngGetGlyphOutline(font, indices[idx],
6115 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6117 size->cx += FONT_GM(font,indices[idx])->adv;
6119 if (! pnfit || ext <= max_ext) {
6129 LeaveCriticalSection( &freetype_cs );
6130 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6134 /*************************************************************
6135 * WineEngGetFontData
6138 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6141 FT_Face ft_face = font->ft_face;
6145 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6146 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6147 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6149 if(!FT_IS_SFNT(ft_face))
6157 if(table) { /* MS tags differ in endianness from FT ones */
6158 table = table >> 24 | table << 24 |
6159 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6162 /* make sure value of len is the value freetype says it needs */
6165 FT_ULong needed = 0;
6166 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6167 if( !err && needed < len) len = needed;
6169 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6172 TRACE("Can't find table %c%c%c%c\n",
6173 /* bytes were reversed */
6174 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6175 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6181 /*************************************************************
6182 * WineEngGetTextFace
6185 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6187 INT n = strlenW(font->name) + 1;
6189 lstrcpynW(str, font->name, count);
6190 return min(count, n);
6195 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6197 if (fs) *fs = font->fs;
6198 return font->charset;
6201 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6203 GdiFont *font = dc->gdiFont, *linked_font;
6204 struct list *first_hfont;
6208 EnterCriticalSection( &freetype_cs );
6209 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6210 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6211 if(font == linked_font)
6212 *new_hfont = dc->hFont;
6215 first_hfont = list_head(&linked_font->hfontlist);
6216 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6218 LeaveCriticalSection( &freetype_cs );
6222 /* Retrieve a list of supported Unicode ranges for a given font.
6223 * Can be called with NULL gs to calculate the buffer size. Returns
6224 * the number of ranges found.
6226 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6228 DWORD num_ranges = 0;
6230 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6233 FT_ULong char_code, char_code_prev;
6236 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6238 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6239 face->num_glyphs, glyph_code, char_code);
6241 if (!glyph_code) return 0;
6245 gs->ranges[0].wcLow = (USHORT)char_code;
6246 gs->ranges[0].cGlyphs = 0;
6247 gs->cGlyphsSupported = 0;
6253 if (char_code < char_code_prev)
6255 ERR("expected increasing char code from FT_Get_Next_Char\n");
6258 if (char_code - char_code_prev > 1)
6263 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6264 gs->ranges[num_ranges - 1].cGlyphs = 1;
6265 gs->cGlyphsSupported++;
6270 gs->ranges[num_ranges - 1].cGlyphs++;
6271 gs->cGlyphsSupported++;
6273 char_code_prev = char_code;
6274 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6278 FIXME("encoding %u not supported\n", face->charmap->encoding);
6283 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6286 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6288 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6291 glyphset->cbThis = size;
6292 glyphset->cRanges = num_ranges;
6293 glyphset->flAccel = 0;
6298 /*************************************************************
6301 BOOL WineEngFontIsLinked(GdiFont *font)
6305 EnterCriticalSection( &freetype_cs );
6306 ret = !list_empty(&font->child_fonts);
6307 LeaveCriticalSection( &freetype_cs );
6311 static BOOL is_hinting_enabled(void)
6313 /* Use the >= 2.2.0 function if available */
6314 if(pFT_Get_TrueType_Engine_Type)
6316 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6317 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6319 #ifdef FT_DRIVER_HAS_HINTER
6324 /* otherwise if we've been compiled with < 2.2.0 headers
6325 use the internal macro */
6326 mod = pFT_Get_Module(library, "truetype");
6327 if(mod && FT_DRIVER_HAS_HINTER(mod))
6335 static BOOL is_subpixel_rendering_enabled( void )
6337 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6338 return pFT_Library_SetLcdFilter &&
6339 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6345 /*************************************************************************
6346 * GetRasterizerCaps (GDI32.@)
6348 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6350 static int hinting = -1;
6351 static int subpixel = -1;
6355 hinting = is_hinting_enabled();
6356 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6359 if ( subpixel == -1 )
6361 subpixel = is_subpixel_rendering_enabled();
6362 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6365 lprs->nSize = sizeof(RASTERIZER_STATUS);
6366 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6368 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6369 lprs->nLanguageID = 0;
6373 /*************************************************************
6374 * WineEngRealizationInfo
6376 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6378 FIXME("(%p, %p): stub!\n", font, info);
6381 if(FT_IS_SCALABLE(font->ft_face))
6384 info->cache_num = font->cache_num;
6385 info->unknown2 = -1;
6389 /*************************************************************************
6390 * Kerning support for TrueType fonts
6392 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6394 struct TT_kern_table
6400 struct TT_kern_subtable
6409 USHORT horizontal : 1;
6411 USHORT cross_stream: 1;
6412 USHORT override : 1;
6413 USHORT reserved1 : 4;
6419 struct TT_format0_kern_subtable
6423 USHORT entrySelector;
6434 static DWORD parse_format0_kern_subtable(GdiFont *font,
6435 const struct TT_format0_kern_subtable *tt_f0_ks,
6436 const USHORT *glyph_to_char,
6437 KERNINGPAIR *kern_pair, DWORD cPairs)
6440 const struct TT_kern_pair *tt_kern_pair;
6442 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6444 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6446 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6447 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6448 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6450 if (!kern_pair || !cPairs)
6453 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6455 nPairs = min(nPairs, cPairs);
6457 for (i = 0; i < nPairs; i++)
6459 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6460 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6461 /* this algorithm appears to better match what Windows does */
6462 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6463 if (kern_pair->iKernAmount < 0)
6465 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6466 kern_pair->iKernAmount -= font->ppem;
6468 else if (kern_pair->iKernAmount > 0)
6470 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6471 kern_pair->iKernAmount += font->ppem;
6473 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6475 TRACE("left %u right %u value %d\n",
6476 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6480 TRACE("copied %u entries\n", nPairs);
6484 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6488 const struct TT_kern_table *tt_kern_table;
6489 const struct TT_kern_subtable *tt_kern_subtable;
6491 USHORT *glyph_to_char;
6494 EnterCriticalSection( &freetype_cs );
6495 if (font->total_kern_pairs != (DWORD)-1)
6497 if (cPairs && kern_pair)
6499 cPairs = min(cPairs, font->total_kern_pairs);
6500 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6501 LeaveCriticalSection( &freetype_cs );
6504 LeaveCriticalSection( &freetype_cs );
6505 return font->total_kern_pairs;
6508 font->total_kern_pairs = 0;
6510 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6512 if (length == GDI_ERROR)
6514 TRACE("no kerning data in the font\n");
6515 LeaveCriticalSection( &freetype_cs );
6519 buf = HeapAlloc(GetProcessHeap(), 0, length);
6522 WARN("Out of memory\n");
6523 LeaveCriticalSection( &freetype_cs );
6527 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6529 /* build a glyph index to char code map */
6530 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6533 WARN("Out of memory allocating a glyph index to char code map\n");
6534 HeapFree(GetProcessHeap(), 0, buf);
6535 LeaveCriticalSection( &freetype_cs );
6539 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6545 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6547 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6548 font->ft_face->num_glyphs, glyph_code, char_code);
6552 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6554 /* FIXME: This doesn't match what Windows does: it does some fancy
6555 * things with duplicate glyph index to char code mappings, while
6556 * we just avoid overriding existing entries.
6558 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6559 glyph_to_char[glyph_code] = (USHORT)char_code;
6561 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6568 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6569 for (n = 0; n <= 65535; n++)
6570 glyph_to_char[n] = (USHORT)n;
6573 tt_kern_table = buf;
6574 nTables = GET_BE_WORD(tt_kern_table->nTables);
6575 TRACE("version %u, nTables %u\n",
6576 GET_BE_WORD(tt_kern_table->version), nTables);
6578 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6580 for (i = 0; i < nTables; i++)
6582 struct TT_kern_subtable tt_kern_subtable_copy;
6584 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6585 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6586 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6588 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6589 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6590 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6592 /* According to the TrueType specification this is the only format
6593 * that will be properly interpreted by Windows and OS/2
6595 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6597 DWORD new_chunk, old_total = font->total_kern_pairs;
6599 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6600 glyph_to_char, NULL, 0);
6601 font->total_kern_pairs += new_chunk;
6603 if (!font->kern_pairs)
6604 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6605 font->total_kern_pairs * sizeof(*font->kern_pairs));
6607 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6608 font->total_kern_pairs * sizeof(*font->kern_pairs));
6610 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6611 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6614 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6616 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6619 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6620 HeapFree(GetProcessHeap(), 0, buf);
6622 if (cPairs && kern_pair)
6624 cPairs = min(cPairs, font->total_kern_pairs);
6625 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6626 LeaveCriticalSection( &freetype_cs );
6629 LeaveCriticalSection( &freetype_cs );
6630 return font->total_kern_pairs;
6633 #else /* HAVE_FREETYPE */
6635 /*************************************************************************/
6637 BOOL WineEngInit(void)
6641 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6645 BOOL WineEngDestroyFontInstance(HFONT hfont)
6650 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6655 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6656 LPWORD pgi, DWORD flags)
6661 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6662 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6665 ERR("called but we don't have FreeType\n");
6669 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6671 ERR("called but we don't have FreeType\n");
6675 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6676 OUTLINETEXTMETRICW *potm)
6678 ERR("called but we don't have FreeType\n");
6682 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6685 ERR("called but we don't have FreeType\n");
6689 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6692 ERR("called but we don't have FreeType\n");
6696 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6698 ERR("called but we don't have FreeType\n");
6702 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6705 ERR("called but we don't have FreeType\n");
6709 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6710 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6712 ERR("called but we don't have FreeType\n");
6716 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6717 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6719 ERR("called but we don't have FreeType\n");
6723 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6726 ERR("called but we don't have FreeType\n");
6730 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6732 ERR("called but we don't have FreeType\n");
6736 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6738 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6742 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6744 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6748 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6750 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6754 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6756 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6757 return DEFAULT_CHARSET;
6760 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6765 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6767 FIXME("(%p, %p): stub\n", font, glyphset);
6771 BOOL WineEngFontIsLinked(GdiFont *font)
6776 /*************************************************************************
6777 * GetRasterizerCaps (GDI32.@)
6779 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6781 lprs->nSize = sizeof(RASTERIZER_STATUS);
6783 lprs->nLanguageID = 0;
6787 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6789 ERR("called but we don't have FreeType\n");
6793 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6795 ERR("called but we don't have FreeType\n");
6799 #endif /* HAVE_FREETYPE */