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_FTTRIGON_H
121 #include <freetype/fttrigon.h>
123 #ifdef HAVE_FREETYPE_FTWINFNT_H
124 #include <freetype/ftwinfnt.h>
126 #ifdef HAVE_FREETYPE_FTMODAPI_H
127 #include <freetype/ftmodapi.h>
129 #ifdef HAVE_FREETYPE_FTLCDFIL_H
130 #include <freetype/ftlcdfil.h>
133 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
137 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
138 FT_TRUETYPE_ENGINE_TYPE_PATENTED
139 } FT_TrueTypeEngineType;
142 static FT_Library library = 0;
149 static FT_Version_t FT_Version;
150 static DWORD FT_SimpleVersion;
152 static void *ft_handle = NULL;
154 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
155 MAKE_FUNCPTR(FT_Done_Face);
156 MAKE_FUNCPTR(FT_Get_Char_Index);
157 MAKE_FUNCPTR(FT_Get_First_Char);
158 MAKE_FUNCPTR(FT_Get_Module);
159 MAKE_FUNCPTR(FT_Get_Next_Char);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Library_Version);
166 MAKE_FUNCPTR(FT_Load_Glyph);
167 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
168 MAKE_FUNCPTR(FT_Matrix_Multiply);
169 #ifdef FT_MULFIX_INLINED
170 #define pFT_MulFix FT_MULFIX_INLINED
172 MAKE_FUNCPTR(FT_MulFix);
174 MAKE_FUNCPTR(FT_New_Face);
175 MAKE_FUNCPTR(FT_New_Memory_Face);
176 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
177 MAKE_FUNCPTR(FT_Outline_Transform);
178 MAKE_FUNCPTR(FT_Outline_Translate);
179 MAKE_FUNCPTR(FT_Render_Glyph);
180 MAKE_FUNCPTR(FT_Select_Charmap);
181 MAKE_FUNCPTR(FT_Set_Charmap);
182 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
183 MAKE_FUNCPTR(FT_Vector_Transform);
184 MAKE_FUNCPTR(FT_Vector_Unit);
185 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
186 #ifdef HAVE_FREETYPE_FTLCDFIL_H
187 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #ifdef SONAME_LIBFONTCONFIG
191 #include <fontconfig/fontconfig.h>
192 MAKE_FUNCPTR(FcConfigGetCurrent);
193 MAKE_FUNCPTR(FcFontList);
194 MAKE_FUNCPTR(FcFontSetDestroy);
195 MAKE_FUNCPTR(FcInit);
196 MAKE_FUNCPTR(FcObjectSetAdd);
197 MAKE_FUNCPTR(FcObjectSetCreate);
198 MAKE_FUNCPTR(FcObjectSetDestroy);
199 MAKE_FUNCPTR(FcPatternCreate);
200 MAKE_FUNCPTR(FcPatternDestroy);
201 MAKE_FUNCPTR(FcPatternGetBool);
202 MAKE_FUNCPTR(FcPatternGetString);
208 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
209 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
210 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #ifndef ft_encoding_none
214 #define FT_ENCODING_NONE ft_encoding_none
216 #ifndef ft_encoding_ms_symbol
217 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
219 #ifndef ft_encoding_unicode
220 #define FT_ENCODING_UNICODE ft_encoding_unicode
222 #ifndef ft_encoding_apple_roman
223 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #ifdef WORDS_BIGENDIAN
227 #define GET_BE_WORD(x) (x)
229 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
239 FT_Short internal_leading;
242 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
243 So to let this compile on older versions of FreeType we'll define the
244 new structure here. */
246 FT_Short height, width;
247 FT_Pos size, x_ppem, y_ppem;
253 NEWTEXTMETRICEXW ntm;
257 typedef struct tagFace {
263 DWORD font_data_size;
266 FONTSIGNATURE fs_links;
268 FT_Fixed font_version;
270 Bitmap_Size size; /* set if face is a bitmap */
271 BOOL external; /* TRUE if we should manually add this font to the registry */
272 struct tagFamily *family;
273 /* Cached data for Enum */
274 struct enum_data *cached_enum_data;
277 typedef struct tagFamily {
279 const WCHAR *FamilyName;
280 const WCHAR *EnglishName;
286 INT adv; /* These three hold to widths of the unrotated chars */
304 typedef struct tagHFONTLIST {
319 struct list hfontlist;
320 OUTLINETEXTMETRICW *potm;
321 DWORD total_kern_pairs;
322 KERNINGPAIR *kern_pairs;
323 struct list child_fonts;
325 /* the following members can be accessed without locking, they are never modified after creation */
327 struct font_mapping *mapping;
350 const WCHAR *font_name;
354 struct enum_charset_element {
360 struct enum_charset_list {
362 struct enum_charset_element element[32];
365 #define GM_BLOCK_SIZE 128
366 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
368 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
369 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
370 #define UNUSED_CACHE_SIZE 10
371 static struct list child_font_list = LIST_INIT(child_font_list);
372 static struct list system_links = LIST_INIT(system_links);
374 static struct list font_subst_list = LIST_INIT(font_subst_list);
376 static struct list font_list = LIST_INIT(font_list);
378 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
379 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
380 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
382 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
383 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
384 'W','i','n','d','o','w','s','\\',
385 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
386 'F','o','n','t','s','\0'};
388 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
389 'W','i','n','d','o','w','s',' ','N','T','\\',
390 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
391 'F','o','n','t','s','\0'};
393 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
394 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
395 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
396 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
398 static const WCHAR * const SystemFontValues[4] = {
405 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
406 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
408 /* Interesting and well-known (frequently-assumed!) font names */
409 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
410 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 };
411 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
412 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
413 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
414 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
415 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
416 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
418 static const WCHAR arial[] = {'A','r','i','a','l',0};
419 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
420 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
421 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
422 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
423 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
424 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
425 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
426 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
428 static const WCHAR *default_serif_list[] =
432 bitstream_vera_serif,
436 static const WCHAR *default_fixed_list[] =
440 bitstream_vera_sans_mono,
444 static const WCHAR *default_sans_list[] =
453 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
454 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
455 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
456 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
457 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
458 'E','u','r','o','p','e','a','n','\0'};
459 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
460 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
461 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
462 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
463 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
464 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
465 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
466 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
467 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
468 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
469 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
470 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
472 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
482 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
490 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
499 typedef struct tagFontSubst {
505 /* Registry font cache key and value names */
506 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
507 'F','o','n','t','s',0};
508 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
509 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
510 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
511 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
512 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
513 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
514 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
515 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
516 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
517 static const WCHAR face_size_value[] = {'S','i','z','e',0};
518 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
519 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
520 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
521 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
522 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
535 static struct list mappings_list = LIST_INIT( mappings_list );
537 static CRITICAL_SECTION freetype_cs;
538 static CRITICAL_SECTION_DEBUG critsect_debug =
541 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
542 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
544 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
546 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
548 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
549 static BOOL use_default_fallback = FALSE;
551 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
553 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
554 'W','i','n','d','o','w','s',' ','N','T','\\',
555 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
556 'S','y','s','t','e','m','L','i','n','k',0};
558 /****************************************
559 * Notes on .fon files
561 * The fonts System, FixedSys and Terminal are special. There are typically multiple
562 * versions installed for different resolutions and codepages. Windows stores which one to use
563 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
565 * FIXEDFON.FON FixedSys
567 * OEMFONT.FON Terminal
568 * LogPixels Current dpi set by the display control panel applet
569 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
570 * also has a LogPixels value that appears to mirror this)
572 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
573 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
574 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
575 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
576 * so that makes sense.
578 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
579 * to be mapped into the registry on Windows 2000 at least).
582 * ega80woa.fon=ega80850.fon
583 * ega40woa.fon=ega40850.fon
584 * cga80woa.fon=cga80850.fon
585 * cga40woa.fon=cga40850.fon
588 /* These are all structures needed for the GSUB table */
590 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
591 #define TATEGAKI_LOWER_BOUND 0x02F1
607 GSUB_ScriptRecord ScriptRecord[1];
613 } GSUB_LangSysRecord;
618 GSUB_LangSysRecord LangSysRecord[1];
622 WORD LookupOrder; /* Reserved */
623 WORD ReqFeatureIndex;
625 WORD FeatureIndex[1];
631 } GSUB_FeatureRecord;
635 GSUB_FeatureRecord FeatureRecord[1];
639 WORD FeatureParams; /* Reserved */
641 WORD LookupListIndex[1];
660 } GSUB_CoverageFormat1;
665 WORD StartCoverageIndex;
671 GSUB_RangeRecord RangeRecord[1];
672 } GSUB_CoverageFormat2;
675 WORD SubstFormat; /* = 1 */
678 } GSUB_SingleSubstFormat1;
681 WORD SubstFormat; /* = 2 */
685 }GSUB_SingleSubstFormat2;
687 #ifdef HAVE_CARBON_CARBON_H
688 static char *find_cache_dir(void)
692 static char cached_path[MAX_PATH];
693 static const char *wine = "/Wine", *fonts = "/Fonts";
695 if(*cached_path) return cached_path;
697 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
700 WARN("can't create cached data folder\n");
703 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
706 WARN("can't create cached data path\n");
710 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
712 ERR("Could not create full path\n");
716 strcat(cached_path, wine);
718 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
720 WARN("Couldn't mkdir %s\n", cached_path);
724 strcat(cached_path, fonts);
725 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
727 WARN("Couldn't mkdir %s\n", cached_path);
734 /******************************************************************
737 * Extracts individual TrueType font files from a Mac suitcase font
738 * and saves them into the user's caches directory (see
740 * Returns a NULL terminated array of filenames.
742 * We do this because they are apps that try to read ttf files
743 * themselves and they don't like Mac suitcase files.
745 static char **expand_mac_font(const char *path)
752 const char *filename;
756 unsigned int size, max_size;
759 TRACE("path %s\n", path);
761 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
764 WARN("failed to get ref\n");
768 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
771 TRACE("no data fork, so trying resource fork\n");
772 res_ref = FSOpenResFile(&ref, fsRdPerm);
775 TRACE("unable to open resource fork\n");
782 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
785 CloseResFile(res_ref);
789 out_dir = find_cache_dir();
791 filename = strrchr(path, '/');
792 if(!filename) filename = path;
795 /* output filename has the form out_dir/filename_%04x.ttf */
796 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
803 unsigned short *num_faces_ptr, num_faces, face;
806 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
808 fond = Get1IndResource(fond_res, idx);
810 TRACE("got fond resource %d\n", idx);
813 fam_rec = *(FamRec**)fond;
814 num_faces_ptr = (unsigned short *)(fam_rec + 1);
815 num_faces = GET_BE_WORD(*num_faces_ptr);
817 assoc = (AsscEntry*)(num_faces_ptr + 1);
818 TRACE("num faces %04x\n", num_faces);
819 for(face = 0; face < num_faces; face++, assoc++)
822 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
823 unsigned short size, font_id;
826 size = GET_BE_WORD(assoc->fontSize);
827 font_id = GET_BE_WORD(assoc->fontID);
830 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
834 TRACE("trying to load sfnt id %04x\n", font_id);
835 sfnt = GetResource(sfnt_res, font_id);
838 TRACE("can't get sfnt resource %04x\n", font_id);
842 output = HeapAlloc(GetProcessHeap(), 0, output_len);
847 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
849 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
850 if(fd != -1 || errno == EEXIST)
854 unsigned char *sfnt_data;
857 sfnt_data = *(unsigned char**)sfnt;
858 write(fd, sfnt_data, GetHandleSize(sfnt));
862 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
865 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
867 ret.array[ret.size++] = output;
871 WARN("unable to create %s\n", output);
872 HeapFree(GetProcessHeap(), 0, output);
875 ReleaseResource(sfnt);
878 ReleaseResource(fond);
881 CloseResFile(res_ref);
886 #endif /* HAVE_CARBON_CARBON_H */
888 static inline BOOL is_win9x(void)
890 return GetVersion() & 0x80000000;
893 This function builds an FT_Fixed from a double. It fails if the absolute
894 value of the float number is greater than 32768.
896 static inline FT_Fixed FT_FixedFromFloat(double f)
902 This function builds an FT_Fixed from a FIXED. It simply put f.value
903 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
905 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
907 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
911 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
916 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
917 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
919 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
920 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
922 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
924 if(face_name && strcmpiW(face_name, family->FamilyName))
926 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
930 file = strrchr(face->file, '/');
935 if(!strcasecmp(file, file_nameA))
937 HeapFree(GetProcessHeap(), 0, file_nameA);
942 HeapFree(GetProcessHeap(), 0, file_nameA);
946 static Family *find_family_from_name(const WCHAR *name)
950 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
952 if(!strcmpiW(family->FamilyName, name))
959 static void DumpSubstList(void)
963 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
965 if(psub->from.charset != -1 || psub->to.charset != -1)
966 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
967 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
969 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
970 debugstr_w(psub->to.name));
975 static LPWSTR strdupW(LPCWSTR p)
978 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
979 ret = HeapAlloc(GetProcessHeap(), 0, len);
984 static LPSTR strdupA(LPCSTR p)
987 DWORD len = (strlen(p) + 1);
988 ret = HeapAlloc(GetProcessHeap(), 0, len);
993 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
998 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1000 if(!strcmpiW(element->from.name, from_name) &&
1001 (element->from.charset == from_charset ||
1002 element->from.charset == -1))
1009 #define ADD_FONT_SUBST_FORCE 1
1011 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1013 FontSubst *from_exist, *to_exist;
1015 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1017 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1019 list_remove(&from_exist->entry);
1020 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1021 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1022 HeapFree(GetProcessHeap(), 0, from_exist);
1028 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1032 HeapFree(GetProcessHeap(), 0, subst->to.name);
1033 subst->to.name = strdupW(to_exist->to.name);
1036 list_add_tail(subst_list, &subst->entry);
1041 HeapFree(GetProcessHeap(), 0, subst->from.name);
1042 HeapFree(GetProcessHeap(), 0, subst->to.name);
1043 HeapFree(GetProcessHeap(), 0, subst);
1047 static void split_subst_info(NameCs *nc, LPSTR str)
1049 CHAR *p = strrchr(str, ',');
1054 nc->charset = strtol(p+1, NULL, 10);
1057 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1058 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1059 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1062 static void LoadSubstList(void)
1066 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1070 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1071 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1072 &hkey) == ERROR_SUCCESS) {
1074 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1075 &valuelen, &datalen, NULL, NULL);
1077 valuelen++; /* returned value doesn't include room for '\0' */
1078 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1079 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1083 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1084 &dlen) == ERROR_SUCCESS) {
1085 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1087 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1088 split_subst_info(&psub->from, value);
1089 split_subst_info(&psub->to, data);
1091 /* Win 2000 doesn't allow mapping between different charsets
1092 or mapping of DEFAULT_CHARSET */
1093 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1094 psub->to.charset == DEFAULT_CHARSET) {
1095 HeapFree(GetProcessHeap(), 0, psub->to.name);
1096 HeapFree(GetProcessHeap(), 0, psub->from.name);
1097 HeapFree(GetProcessHeap(), 0, psub);
1099 add_font_subst(&font_subst_list, psub, 0);
1101 /* reset dlen and vlen */
1105 HeapFree(GetProcessHeap(), 0, data);
1106 HeapFree(GetProcessHeap(), 0, value);
1112 /*****************************************************************
1113 * get_name_table_entry
1115 * Supply the platform, encoding, language and name ids in req
1116 * and if the name exists the function will fill in the string
1117 * and string_len members. The string is owned by FreeType so
1118 * don't free it. Returns TRUE if the name is found else FALSE.
1120 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1123 FT_UInt num_names, name_index;
1125 if(FT_IS_SFNT(ft_face))
1127 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1129 for(name_index = 0; name_index < num_names; name_index++)
1131 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1133 if((name.platform_id == req->platform_id) &&
1134 (name.encoding_id == req->encoding_id) &&
1135 (name.language_id == req->language_id) &&
1136 (name.name_id == req->name_id))
1138 req->string = name.string;
1139 req->string_len = name.string_len;
1146 req->string_len = 0;
1150 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1155 name.platform_id = TT_PLATFORM_MICROSOFT;
1156 name.encoding_id = TT_MS_ID_UNICODE_CS;
1157 name.language_id = language_id;
1158 name.name_id = name_id;
1160 if(get_name_table_entry(ft_face, &name))
1164 /* String is not nul terminated and string_len is a byte length. */
1165 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1166 for(i = 0; i < name.string_len / 2; i++)
1168 WORD *tmp = (WORD *)&name.string[i * 2];
1169 ret[i] = GET_BE_WORD(*tmp);
1172 TRACE("Got localised name %s\n", debugstr_w(ret));
1178 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1181 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1182 if(r != ERROR_SUCCESS) return r;
1183 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1184 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1187 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1189 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1192 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1195 DWORD num_strikes, max_strike_key_len;
1197 /* If we have a File Name key then this is a real font, not just the parent
1198 key of a bunch of non-scalable strikes */
1199 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1203 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1204 face->cached_enum_data = NULL;
1206 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1207 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1209 face->StyleName = strdupW(face_name);
1210 face->family = family;
1212 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1214 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1215 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1216 face->FullName = fullName;
1219 face->FullName = NULL;
1221 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1222 reg_load_dword(hkey_face, face_italic_value, &italic);
1223 reg_load_dword(hkey_face, face_bold_value, &bold);
1224 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1225 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1227 needed = sizeof(face->fs);
1228 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1229 memset(&face->fs_links, 0, sizeof(face->fs_links));
1231 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1233 face->scalable = TRUE;
1234 memset(&face->size, 0, sizeof(face->size));
1238 face->scalable = FALSE;
1239 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1240 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1241 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1242 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1243 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1245 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1246 face->size.height, face->size.width, face->size.size >> 6,
1247 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1251 if (italic) face->ntmFlags |= NTM_ITALIC;
1252 if (bold) face->ntmFlags |= NTM_BOLD;
1253 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1255 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1256 face->fs.fsCsb[0], face->fs.fsCsb[1],
1257 face->fs.fsUsb[0], face->fs.fsUsb[1],
1258 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1260 if(!italic && !bold)
1261 list_add_head(&family->faces, &face->entry);
1263 list_add_tail(&family->faces, &face->entry);
1265 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1268 /* do we have any bitmap strikes? */
1269 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1270 NULL, NULL, NULL, NULL);
1271 if(num_strikes != 0)
1273 WCHAR strike_name[10];
1274 DWORD strike_index = 0;
1276 needed = sizeof(strike_name) / sizeof(WCHAR);
1277 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1278 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1281 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1282 load_face(hkey_strike, face_name, family);
1283 RegCloseKey(hkey_strike);
1284 needed = sizeof(strike_name) / sizeof(WCHAR);
1289 static void load_font_list_from_cache(HKEY hkey_font_cache)
1291 DWORD max_family_key_len, size;
1293 DWORD family_index = 0;
1297 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1298 NULL, NULL, NULL, NULL);
1299 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1301 size = max_family_key_len + 1;
1302 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1303 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1305 WCHAR *english_family = NULL;
1306 DWORD face_index = 0;
1308 DWORD max_face_key_len;
1310 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1311 TRACE("opened family key %s\n", debugstr_w(family_name));
1312 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1314 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1315 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1318 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1319 family->FamilyName = strdupW(family_name);
1320 family->EnglishName = english_family;
1321 list_init(&family->faces);
1322 list_add_tail(&font_list, &family->entry);
1326 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1327 subst->from.name = strdupW(english_family);
1328 subst->from.charset = -1;
1329 subst->to.name = strdupW(family_name);
1330 subst->to.charset = -1;
1331 add_font_subst(&font_subst_list, subst, 0);
1334 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1335 NULL, NULL, NULL, NULL);
1337 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1338 size = max_face_key_len + 1;
1339 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1340 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1344 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1345 load_face(hkey_face, face_name, family);
1346 RegCloseKey(hkey_face);
1347 size = max_face_key_len + 1;
1349 HeapFree(GetProcessHeap(), 0, face_name);
1350 RegCloseKey(hkey_family);
1351 size = max_family_key_len + 1;
1354 HeapFree(GetProcessHeap(), 0, family_name);
1357 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1360 HKEY hkey_wine_fonts;
1362 /* We don't want to create the fonts key as volatile, so open this first */
1363 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1364 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1365 if(ret != ERROR_SUCCESS)
1367 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1371 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1372 KEY_ALL_ACCESS, NULL, hkey, disposition);
1373 RegCloseKey(hkey_wine_fonts);
1377 static void add_face_to_cache(Face *face)
1379 HKEY hkey_font_cache, hkey_family, hkey_face;
1380 WCHAR *face_key_name;
1382 create_font_cache_key(&hkey_font_cache, NULL);
1384 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1385 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1386 if(face->family->EnglishName)
1387 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1388 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1391 face_key_name = face->StyleName;
1394 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1395 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1396 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1398 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1401 HeapFree(GetProcessHeap(), 0, face_key_name);
1403 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1405 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1406 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1408 reg_save_dword(hkey_face, face_index_value, face->face_index);
1409 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1410 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1411 reg_save_dword(hkey_face, face_version_value, face->font_version);
1412 reg_save_dword(hkey_face, face_external_value, face->external);
1414 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1418 reg_save_dword(hkey_face, face_height_value, face->size.height);
1419 reg_save_dword(hkey_face, face_width_value, face->size.width);
1420 reg_save_dword(hkey_face, face_size_value, face->size.size);
1421 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1422 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1423 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1425 RegCloseKey(hkey_face);
1426 RegCloseKey(hkey_family);
1427 RegCloseKey(hkey_font_cache);
1430 static inline int TestStyles(DWORD flags, DWORD styles)
1432 return (flags & styles) == styles;
1435 static int StyleOrdering(Face *face)
1437 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1439 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1441 if (TestStyles(face->ntmFlags, NTM_BOLD))
1443 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1446 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1447 debugstr_w(face->family->FamilyName),
1448 debugstr_w(face->StyleName),
1454 /* Add a style of face to a font family using an ordering of the list such
1455 that regular fonts come before bold and italic, and single styles come
1456 before compound styles. */
1457 static void AddFaceToFamily(Face *face, Family *family)
1461 LIST_FOR_EACH( entry, &family->faces )
1463 Face *ent = LIST_ENTRY(entry, Face, entry);
1464 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1466 list_add_before( entry, &face->entry );
1469 #define ADDFONT_EXTERNAL_FONT 0x01
1470 #define ADDFONT_FORCE_BITMAP 0x02
1471 #define ADDFONT_ADD_TO_CACHE 0x04
1473 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1477 TT_Header *pHeader = NULL;
1478 WCHAR *english_family, *localised_family, *StyleW;
1482 struct list *family_elem_ptr, *face_elem_ptr;
1484 FT_Long face_index = 0, num_faces;
1485 FT_WinFNT_HeaderRec winfnt_header;
1486 int i, bitmap_num, internal_leading;
1489 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1490 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1492 #ifdef HAVE_CARBON_CARBON_H
1493 if(file && !fake_family)
1495 char **mac_list = expand_mac_font(file);
1498 BOOL had_one = FALSE;
1500 for(cursor = mac_list; *cursor; cursor++)
1503 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1504 HeapFree(GetProcessHeap(), 0, *cursor);
1506 HeapFree(GetProcessHeap(), 0, mac_list);
1511 #endif /* HAVE_CARBON_CARBON_H */
1514 char *family_name = fake_family;
1518 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1519 err = pFT_New_Face(library, file, face_index, &ft_face);
1522 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1523 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1527 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1531 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*/
1532 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1533 pFT_Done_Face(ft_face);
1537 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1538 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1539 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1540 pFT_Done_Face(ft_face);
1544 if(FT_IS_SFNT(ft_face))
1546 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1547 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1548 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1550 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1551 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1552 pFT_Done_Face(ft_face);
1556 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1557 we don't want to load these. */
1558 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1562 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1564 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1565 pFT_Done_Face(ft_face);
1571 if(!ft_face->family_name || !ft_face->style_name) {
1572 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1573 pFT_Done_Face(ft_face);
1577 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1579 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1580 pFT_Done_Face(ft_face);
1586 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1587 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1589 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1590 HeapFree(GetProcessHeap(), 0, localised_family);
1591 num_faces = ft_face->num_faces;
1592 pFT_Done_Face(ft_face);
1595 HeapFree(GetProcessHeap(), 0, localised_family);
1599 family_name = ft_face->family_name;
1603 My_FT_Bitmap_Size *size = NULL;
1606 if(!FT_IS_SCALABLE(ft_face))
1607 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1609 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1610 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1611 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1613 localised_family = NULL;
1615 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1616 if(localised_family && !strcmpiW(localised_family, english_family)) {
1617 HeapFree(GetProcessHeap(), 0, localised_family);
1618 localised_family = NULL;
1623 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1624 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1625 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1630 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1631 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1632 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1633 list_init(&family->faces);
1634 list_add_tail(&font_list, &family->entry);
1636 if(localised_family) {
1637 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1638 subst->from.name = strdupW(english_family);
1639 subst->from.charset = -1;
1640 subst->to.name = strdupW(localised_family);
1641 subst->to.charset = -1;
1642 add_font_subst(&font_subst_list, subst, 0);
1645 HeapFree(GetProcessHeap(), 0, localised_family);
1646 HeapFree(GetProcessHeap(), 0, english_family);
1648 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1649 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1650 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1652 internal_leading = 0;
1653 memset(&fs, 0, sizeof(fs));
1655 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1657 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1658 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1659 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1660 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1661 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1662 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1663 if(pOS2->version == 0) {
1666 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1667 fs.fsCsb[0] |= FS_LATIN1;
1669 fs.fsCsb[0] |= FS_SYMBOL;
1672 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1674 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1675 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1676 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1678 internal_leading = winfnt_header.internal_leading;
1681 face_elem_ptr = list_head(&family->faces);
1682 while(face_elem_ptr) {
1683 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1684 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1685 if(!strcmpiW(face->StyleName, StyleW) &&
1686 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1687 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1688 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1689 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1692 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1693 HeapFree(GetProcessHeap(), 0, StyleW);
1694 pFT_Done_Face(ft_face);
1697 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1698 TRACE("Original font is newer so skipping this one\n");
1699 HeapFree(GetProcessHeap(), 0, StyleW);
1700 pFT_Done_Face(ft_face);
1703 TRACE("Replacing original with this one\n");
1704 list_remove(&face->entry);
1705 HeapFree(GetProcessHeap(), 0, face->file);
1706 HeapFree(GetProcessHeap(), 0, face->StyleName);
1707 HeapFree(GetProcessHeap(), 0, face->FullName);
1708 HeapFree(GetProcessHeap(), 0, face);
1713 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1714 face->cached_enum_data = NULL;
1715 face->StyleName = StyleW;
1716 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1719 face->file = strdupA(file);
1720 face->font_data_ptr = NULL;
1721 face->font_data_size = 0;
1726 face->font_data_ptr = font_data_ptr;
1727 face->font_data_size = font_data_size;
1729 face->face_index = face_index;
1731 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1732 face->ntmFlags |= NTM_ITALIC;
1733 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1734 face->ntmFlags |= NTM_BOLD;
1735 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1736 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1737 face->family = family;
1738 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1740 memset(&face->fs_links, 0, sizeof(face->fs_links));
1742 if(FT_IS_SCALABLE(ft_face)) {
1743 memset(&face->size, 0, sizeof(face->size));
1744 face->scalable = TRUE;
1746 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1747 size->height, size->width, size->size >> 6,
1748 size->x_ppem >> 6, size->y_ppem >> 6);
1749 face->size.height = size->height;
1750 face->size.width = size->width;
1751 face->size.size = size->size;
1752 face->size.x_ppem = size->x_ppem;
1753 face->size.y_ppem = size->y_ppem;
1754 face->size.internal_leading = internal_leading;
1755 face->scalable = FALSE;
1758 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1760 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1762 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1763 face->ntmFlags |= NTM_PS_OPENTYPE;
1766 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1767 face->fs.fsCsb[0], face->fs.fsCsb[1],
1768 face->fs.fsUsb[0], face->fs.fsUsb[1],
1769 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1772 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1773 for(i = 0; i < ft_face->num_charmaps; i++) {
1774 switch(ft_face->charmaps[i]->encoding) {
1775 case FT_ENCODING_UNICODE:
1776 case FT_ENCODING_APPLE_ROMAN:
1777 face->fs.fsCsb[0] |= FS_LATIN1;
1779 case FT_ENCODING_MS_SYMBOL:
1780 face->fs.fsCsb[0] |= FS_SYMBOL;
1788 if(flags & ADDFONT_ADD_TO_CACHE)
1789 add_face_to_cache(face);
1791 AddFaceToFamily(face, family);
1793 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1795 num_faces = ft_face->num_faces;
1796 pFT_Done_Face(ft_face);
1797 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1798 debugstr_w(StyleW));
1799 } while(num_faces > ++face_index);
1803 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1805 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1808 static void DumpFontList(void)
1812 struct list *family_elem_ptr, *face_elem_ptr;
1814 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1815 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1816 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1817 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1818 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1819 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1821 TRACE(" %d", face->size.height);
1828 /***********************************************************
1829 * The replacement list is a way to map an entire font
1830 * family onto another family. For example adding
1832 * [HKCU\Software\Wine\Fonts\Replacements]
1833 * "Wingdings"="Winedings"
1835 * would enumerate the Winedings font both as Winedings and
1836 * Wingdings. However if a real Wingdings font is present the
1837 * replacement does not take place.
1840 static void LoadReplaceList(void)
1843 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1848 struct list *family_elem_ptr, *face_elem_ptr;
1851 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1852 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1854 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1855 &valuelen, &datalen, NULL, NULL);
1857 valuelen++; /* returned value doesn't include room for '\0' */
1858 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1859 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1863 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1864 &dlen) == ERROR_SUCCESS) {
1865 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1866 /* "NewName"="Oldname" */
1867 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1869 if(!find_family_from_name(value))
1871 /* Find the old family and hence all of the font files
1873 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1874 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1875 if(!strcmpiW(family->FamilyName, data)) {
1876 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1877 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1878 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1879 debugstr_w(face->StyleName), familyA);
1880 /* Now add a new entry with the new family name */
1881 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1882 familyA, family->FamilyName,
1883 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1889 /* reset dlen and vlen */
1893 HeapFree(GetProcessHeap(), 0, data);
1894 HeapFree(GetProcessHeap(), 0, value);
1899 /*************************************************************
1902 static BOOL init_system_links(void)
1906 DWORD type, max_val, max_data, val_len, data_len, index;
1907 WCHAR *value, *data;
1908 WCHAR *entry, *next;
1909 SYSTEM_LINKS *font_link, *system_font_link;
1910 CHILD_FONT *child_font;
1911 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1912 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1918 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1920 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1921 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1922 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1923 val_len = max_val + 1;
1924 data_len = max_data;
1926 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1928 memset(&fs, 0, sizeof(fs));
1929 psub = get_font_subst(&font_subst_list, value, -1);
1930 /* Don't store fonts that are only substitutes for other fonts */
1933 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1936 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1937 font_link->font_name = strdupW(value);
1938 list_init(&font_link->links);
1939 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1942 CHILD_FONT *child_font;
1944 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1946 next = entry + strlenW(entry) + 1;
1948 face_name = strchrW(entry, ',');
1952 while(isspaceW(*face_name))
1955 psub = get_font_subst(&font_subst_list, face_name, -1);
1957 face_name = psub->to.name;
1959 face = find_face_from_filename(entry, face_name);
1962 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1966 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1967 child_font->face = face;
1968 child_font->font = NULL;
1969 fs.fsCsb[0] |= face->fs.fsCsb[0];
1970 fs.fsCsb[1] |= face->fs.fsCsb[1];
1971 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1972 list_add_tail(&font_link->links, &child_font->entry);
1974 family = find_family_from_name(font_link->font_name);
1977 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1979 face->fs_links = fs;
1982 list_add_tail(&system_links, &font_link->entry);
1984 val_len = max_val + 1;
1985 data_len = max_data;
1988 HeapFree(GetProcessHeap(), 0, value);
1989 HeapFree(GetProcessHeap(), 0, data);
1993 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1996 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1997 system_font_link->font_name = strdupW(System);
1998 list_init(&system_font_link->links);
2000 face = find_face_from_filename(tahoma_ttf, Tahoma);
2003 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2004 child_font->face = face;
2005 child_font->font = NULL;
2006 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2007 list_add_tail(&system_font_link->links, &child_font->entry);
2009 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2011 if(!strcmpiW(font_link->font_name, Tahoma))
2013 CHILD_FONT *font_link_entry;
2014 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2016 CHILD_FONT *new_child;
2017 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2018 new_child->face = font_link_entry->face;
2019 new_child->font = NULL;
2020 list_add_tail(&system_font_link->links, &new_child->entry);
2025 list_add_tail(&system_links, &system_font_link->entry);
2029 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2032 struct dirent *dent;
2033 char path[MAX_PATH];
2035 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2037 dir = opendir(dirname);
2039 WARN("Can't open directory %s\n", debugstr_a(dirname));
2042 while((dent = readdir(dir)) != NULL) {
2043 struct stat statbuf;
2045 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2048 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2050 sprintf(path, "%s/%s", dirname, dent->d_name);
2052 if(stat(path, &statbuf) == -1)
2054 WARN("Can't stat %s\n", debugstr_a(path));
2057 if(S_ISDIR(statbuf.st_mode))
2058 ReadFontDir(path, external_fonts);
2061 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2062 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2063 AddFontFileToList(path, NULL, NULL, addfont_flags);
2070 static void load_fontconfig_fonts(void)
2072 #ifdef SONAME_LIBFONTCONFIG
2073 void *fc_handle = NULL;
2082 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2084 TRACE("Wine cannot find the fontconfig library (%s).\n",
2085 SONAME_LIBFONTCONFIG);
2088 #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;}
2089 LOAD_FUNCPTR(FcConfigGetCurrent);
2090 LOAD_FUNCPTR(FcFontList);
2091 LOAD_FUNCPTR(FcFontSetDestroy);
2092 LOAD_FUNCPTR(FcInit);
2093 LOAD_FUNCPTR(FcObjectSetAdd);
2094 LOAD_FUNCPTR(FcObjectSetCreate);
2095 LOAD_FUNCPTR(FcObjectSetDestroy);
2096 LOAD_FUNCPTR(FcPatternCreate);
2097 LOAD_FUNCPTR(FcPatternDestroy);
2098 LOAD_FUNCPTR(FcPatternGetBool);
2099 LOAD_FUNCPTR(FcPatternGetString);
2102 if(!pFcInit()) return;
2104 config = pFcConfigGetCurrent();
2105 pat = pFcPatternCreate();
2106 os = pFcObjectSetCreate();
2107 pFcObjectSetAdd(os, FC_FILE);
2108 pFcObjectSetAdd(os, FC_SCALABLE);
2109 fontset = pFcFontList(config, pat, os);
2110 if(!fontset) return;
2111 for(i = 0; i < fontset->nfont; i++) {
2114 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2116 TRACE("fontconfig: %s\n", file);
2118 /* We're just interested in OT/TT fonts for now, so this hack just
2119 picks up the scalable fonts without extensions .pf[ab] to save time
2120 loading every other font */
2122 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2124 TRACE("not scalable\n");
2128 len = strlen( file );
2129 if(len < 4) continue;
2130 ext = &file[ len - 3 ];
2131 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2132 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2134 pFcFontSetDestroy(fontset);
2135 pFcObjectSetDestroy(os);
2136 pFcPatternDestroy(pat);
2142 static BOOL load_font_from_data_dir(LPCWSTR file)
2145 const char *data_dir = wine_get_data_dir();
2147 if (!data_dir) data_dir = wine_get_build_dir();
2154 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2156 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2158 strcpy(unix_name, data_dir);
2159 strcat(unix_name, "/fonts/");
2161 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2163 EnterCriticalSection( &freetype_cs );
2164 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2165 LeaveCriticalSection( &freetype_cs );
2166 HeapFree(GetProcessHeap(), 0, unix_name);
2171 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2173 static const WCHAR slashW[] = {'\\','\0'};
2175 WCHAR windowsdir[MAX_PATH];
2178 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2179 strcatW(windowsdir, fontsW);
2180 strcatW(windowsdir, slashW);
2181 strcatW(windowsdir, file);
2182 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2183 EnterCriticalSection( &freetype_cs );
2184 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2185 LeaveCriticalSection( &freetype_cs );
2186 HeapFree(GetProcessHeap(), 0, unixname);
2191 static void load_system_fonts(void)
2194 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2195 const WCHAR * const *value;
2197 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2200 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2201 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2202 strcatW(windowsdir, fontsW);
2203 for(value = SystemFontValues; *value; value++) {
2204 dlen = sizeof(data);
2205 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2209 sprintfW(pathW, fmtW, windowsdir, data);
2210 if((unixname = wine_get_unix_file_name(pathW))) {
2211 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2212 HeapFree(GetProcessHeap(), 0, unixname);
2215 load_font_from_data_dir(data);
2222 /*************************************************************
2224 * This adds registry entries for any externally loaded fonts
2225 * (fonts from fontconfig or FontDirs). It also deletes entries
2226 * of no longer existing fonts.
2229 static void update_reg_entries(void)
2231 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2236 struct list *family_elem_ptr, *face_elem_ptr;
2238 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2239 static const WCHAR spaceW[] = {' ', '\0'};
2242 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2243 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2244 ERR("Can't create Windows font reg key\n");
2248 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2249 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2250 ERR("Can't create Windows font reg key\n");
2254 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2255 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2256 ERR("Can't create external font reg key\n");
2260 /* enumerate the fonts and add external ones to the two keys */
2262 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2263 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2264 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2265 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2266 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2267 if(!face->external) continue;
2269 if (!(face->ntmFlags & NTM_REGULAR))
2270 len = len_fam + strlenW(face->StyleName) + 1;
2271 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2272 strcpyW(valueW, family->FamilyName);
2273 if(len != len_fam) {
2274 strcatW(valueW, spaceW);
2275 strcatW(valueW, face->StyleName);
2277 strcatW(valueW, TrueType);
2279 file = wine_get_dos_file_name(face->file);
2281 len = strlenW(file) + 1;
2284 if((path = strrchr(face->file, '/')) == NULL)
2288 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2290 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2291 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2293 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2294 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2295 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2297 HeapFree(GetProcessHeap(), 0, file);
2298 HeapFree(GetProcessHeap(), 0, valueW);
2302 if(external_key) RegCloseKey(external_key);
2303 if(win9x_key) RegCloseKey(win9x_key);
2304 if(winnt_key) RegCloseKey(winnt_key);
2308 static void delete_external_font_keys(void)
2310 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2311 DWORD dlen, vlen, datalen, valuelen, i, type;
2315 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2316 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2317 ERR("Can't create Windows font reg key\n");
2321 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2322 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2323 ERR("Can't create Windows font reg key\n");
2327 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2328 ERR("Can't create external font reg key\n");
2332 /* Delete all external fonts added last time */
2334 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2335 &valuelen, &datalen, NULL, NULL);
2336 valuelen++; /* returned value doesn't include room for '\0' */
2337 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2338 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2340 dlen = datalen * sizeof(WCHAR);
2343 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2344 &dlen) == ERROR_SUCCESS) {
2346 RegDeleteValueW(winnt_key, valueW);
2347 RegDeleteValueW(win9x_key, valueW);
2348 /* reset dlen and vlen */
2352 HeapFree(GetProcessHeap(), 0, data);
2353 HeapFree(GetProcessHeap(), 0, valueW);
2355 /* Delete the old external fonts key */
2356 RegCloseKey(external_key);
2357 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2360 if(win9x_key) RegCloseKey(win9x_key);
2361 if(winnt_key) RegCloseKey(winnt_key);
2364 /*************************************************************
2365 * WineEngAddFontResourceEx
2368 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2374 if (ft_handle) /* do it only if we have freetype up and running */
2379 FIXME("Ignoring flags %x\n", flags);
2381 if((unixname = wine_get_unix_file_name(file)))
2383 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2385 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2386 EnterCriticalSection( &freetype_cs );
2387 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2388 LeaveCriticalSection( &freetype_cs );
2389 HeapFree(GetProcessHeap(), 0, unixname);
2391 if (!ret && !strchrW(file, '\\')) {
2392 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2393 ret = load_font_from_winfonts_dir(file);
2395 /* Try in datadir/fonts (or builddir/fonts),
2396 * needed for Magic the Gathering Online
2398 ret = load_font_from_data_dir(file);
2405 /*************************************************************
2406 * WineEngAddFontMemResourceEx
2409 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2413 if (ft_handle) /* do it only if we have freetype up and running */
2415 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2417 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2418 memcpy(pFontCopy, pbFont, cbFont);
2420 EnterCriticalSection( &freetype_cs );
2421 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2422 LeaveCriticalSection( &freetype_cs );
2426 TRACE("AddFontToList failed\n");
2427 HeapFree(GetProcessHeap(), 0, pFontCopy);
2430 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2431 * For now return something unique but quite random
2433 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2434 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2441 /*************************************************************
2442 * WineEngRemoveFontResourceEx
2445 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2448 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2452 static const struct nls_update_font_list
2454 UINT ansi_cp, oem_cp;
2455 const char *oem, *fixed, *system;
2456 const char *courier, *serif, *small, *sserif;
2457 /* these are for font substitutes */
2458 const char *shelldlg, *tmsrmn;
2459 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2463 const char *from, *to;
2464 } arial_0, courier_new_0, times_new_roman_0;
2465 } nls_update_font_list[] =
2467 /* Latin 1 (United States) */
2468 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2469 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2470 "Tahoma","Times New Roman",
2471 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2474 /* Latin 1 (Multilingual) */
2475 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2476 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2477 "Tahoma","Times New Roman", /* FIXME unverified */
2478 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2481 /* Eastern Europe */
2482 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2483 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2484 "Tahoma","Times New Roman", /* FIXME unverified */
2485 "Fixedsys,238", "System,238",
2486 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2487 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2488 { "Arial CE,0", "Arial,238" },
2489 { "Courier New CE,0", "Courier New,238" },
2490 { "Times New Roman CE,0", "Times New Roman,238" }
2493 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2494 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2495 "Tahoma","Times New Roman", /* FIXME unverified */
2496 "Fixedsys,204", "System,204",
2497 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2498 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2499 { "Arial Cyr,0", "Arial,204" },
2500 { "Courier New Cyr,0", "Courier New,204" },
2501 { "Times New Roman Cyr,0", "Times New Roman,204" }
2504 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2505 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2506 "Tahoma","Times New Roman", /* FIXME unverified */
2507 "Fixedsys,161", "System,161",
2508 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2509 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2510 { "Arial Greek,0", "Arial,161" },
2511 { "Courier New Greek,0", "Courier New,161" },
2512 { "Times New Roman Greek,0", "Times New Roman,161" }
2515 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2516 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2517 "Tahoma","Times New Roman", /* FIXME unverified */
2518 "Fixedsys,162", "System,162",
2519 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2520 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2521 { "Arial Tur,0", "Arial,162" },
2522 { "Courier New Tur,0", "Courier New,162" },
2523 { "Times New Roman Tur,0", "Times New Roman,162" }
2526 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2527 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2528 "Tahoma","Times New Roman", /* FIXME unverified */
2529 "Fixedsys,177", "System,177",
2530 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2531 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2535 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2536 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2537 "Tahoma","Times New Roman", /* FIXME unverified */
2538 "Fixedsys,178", "System,178",
2539 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2540 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2544 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2545 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2546 "Tahoma","Times New Roman", /* FIXME unverified */
2547 "Fixedsys,186", "System,186",
2548 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2549 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2550 { "Arial Baltic,0", "Arial,186" },
2551 { "Courier New Baltic,0", "Courier New,186" },
2552 { "Times New Roman Baltic,0", "Times New Roman,186" }
2555 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2556 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2557 "Tahoma","Times New Roman", /* FIXME unverified */
2558 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2562 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2563 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2564 "Tahoma","Times New Roman", /* FIXME unverified */
2565 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2569 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2570 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2571 "MS UI Gothic","MS Serif",
2572 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2575 /* Chinese Simplified */
2576 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2577 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2578 "SimSun", "NSimSun",
2579 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2583 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2584 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2586 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2589 /* Chinese Traditional */
2590 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2591 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2592 "PMingLiU", "MingLiU",
2593 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2598 static const WCHAR *font_links_list[] =
2600 Lucida_Sans_Unicode,
2601 Microsoft_Sans_Serif,
2605 static const struct font_links_defaults_list
2607 /* Keyed off substitution for "MS Shell Dlg" */
2608 const WCHAR *shelldlg;
2609 /* Maximum of four substitutes, plus terminating NULL pointer */
2610 const WCHAR *substitutes[5];
2611 } font_links_defaults_list[] =
2613 /* Non East-Asian */
2614 { Tahoma, /* FIXME unverified ordering */
2615 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2617 /* Below lists are courtesy of
2618 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2622 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2624 /* Chinese Simplified */
2626 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2630 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2632 /* Chinese Traditional */
2634 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2638 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2640 return ( ansi_cp == 932 /* CP932 for Japanese */
2641 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2642 || ansi_cp == 949 /* CP949 for Korean */
2643 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2646 static inline HKEY create_fonts_NT_registry_key(void)
2650 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2651 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2655 static inline HKEY create_fonts_9x_registry_key(void)
2659 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2660 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2664 static inline HKEY create_config_fonts_registry_key(void)
2668 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2669 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2673 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2675 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2676 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2677 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2678 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2681 static void set_value_key(HKEY hkey, const char *name, const char *value)
2684 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2686 RegDeleteValueA(hkey, name);
2689 static void update_font_info(void)
2691 char buf[40], cpbuf[40];
2694 UINT i, ansi_cp = 0, oem_cp = 0;
2697 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2700 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2701 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2702 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2703 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2704 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2706 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2707 if (is_dbcs_ansi_cp(ansi_cp))
2708 use_default_fallback = TRUE;
2711 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2713 if (!strcmp( buf, cpbuf )) /* already set correctly */
2718 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2720 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2722 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2725 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2729 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2730 nls_update_font_list[i].oem_cp == oem_cp)
2732 hkey = create_config_fonts_registry_key();
2733 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2734 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2735 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2738 hkey = create_fonts_NT_registry_key();
2739 add_font_list(hkey, &nls_update_font_list[i]);
2742 hkey = create_fonts_9x_registry_key();
2743 add_font_list(hkey, &nls_update_font_list[i]);
2746 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2748 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2749 strlen(nls_update_font_list[i].shelldlg)+1);
2750 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2751 strlen(nls_update_font_list[i].tmsrmn)+1);
2753 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2754 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2755 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2756 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2757 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2758 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2759 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2760 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2762 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2763 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2764 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2772 /* Delete the FontSubstitutes from other locales */
2773 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2775 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2776 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2777 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2783 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2785 /* Clear out system links */
2786 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2789 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2799 WCHAR buff[MAX_PATH];
2803 static const WCHAR comma[] = {',',0};
2805 RegDeleteValueW(hkey, name);
2810 for (i = 0; values[i] != NULL; i++)
2813 if (!strcmpiW(name,value))
2815 psub = get_font_subst(&font_subst_list, value, -1);
2817 value = psub->to.name;
2818 family = find_family_from_name(value);
2822 /* Use first extant filename for this Family */
2823 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2827 file = strrchr(face->file, '/');
2836 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2837 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2838 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2839 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2840 if (sizeof(buff)-(data-buff) < entryLen + 1)
2842 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2843 HeapFree(GetProcessHeap(), 0, fileW);
2846 strcpyW(data, fileW);
2847 strcatW(data, comma);
2848 strcatW(data, value);
2850 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2851 HeapFree(GetProcessHeap(), 0, fileW);
2857 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2859 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2861 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2864 static void update_system_links(void)
2872 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2874 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2876 if (disposition == REG_OPENED_EXISTING_KEY)
2878 TRACE("SystemLink key already exists, doing nothing\n");
2883 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2885 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2890 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2892 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2894 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2895 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2897 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2898 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2901 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2903 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2908 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2910 WARN("failed to create SystemLink key\n");
2914 static BOOL init_freetype(void)
2916 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2919 "Wine cannot find the FreeType font library. To enable Wine to\n"
2920 "use TrueType fonts please install a version of FreeType greater than\n"
2921 "or equal to 2.0.5.\n"
2922 "http://www.freetype.org\n");
2926 #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;}
2928 LOAD_FUNCPTR(FT_Done_Face)
2929 LOAD_FUNCPTR(FT_Get_Char_Index)
2930 LOAD_FUNCPTR(FT_Get_First_Char)
2931 LOAD_FUNCPTR(FT_Get_Module)
2932 LOAD_FUNCPTR(FT_Get_Next_Char)
2933 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2934 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2935 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2936 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2937 LOAD_FUNCPTR(FT_Init_FreeType)
2938 LOAD_FUNCPTR(FT_Library_Version)
2939 LOAD_FUNCPTR(FT_Load_Glyph)
2940 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2941 LOAD_FUNCPTR(FT_Matrix_Multiply)
2942 #ifndef FT_MULFIX_INLINED
2943 LOAD_FUNCPTR(FT_MulFix)
2945 LOAD_FUNCPTR(FT_New_Face)
2946 LOAD_FUNCPTR(FT_New_Memory_Face)
2947 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2948 LOAD_FUNCPTR(FT_Outline_Transform)
2949 LOAD_FUNCPTR(FT_Outline_Translate)
2950 LOAD_FUNCPTR(FT_Render_Glyph)
2951 LOAD_FUNCPTR(FT_Select_Charmap)
2952 LOAD_FUNCPTR(FT_Set_Charmap)
2953 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2954 LOAD_FUNCPTR(FT_Vector_Transform)
2955 LOAD_FUNCPTR(FT_Vector_Unit)
2957 /* Don't warn if these ones are missing */
2958 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2959 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2960 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2963 if(pFT_Init_FreeType(&library) != 0) {
2964 ERR("Can't init FreeType library\n");
2965 wine_dlclose(ft_handle, NULL, 0);
2969 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2971 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2972 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2973 ((FT_Version.minor << 8) & 0x00ff00) |
2974 ((FT_Version.patch ) & 0x0000ff);
2980 "Wine cannot find certain functions that it needs inside the FreeType\n"
2981 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2982 "FreeType to at least version 2.1.4.\n"
2983 "http://www.freetype.org\n");
2984 wine_dlclose(ft_handle, NULL, 0);
2989 static void init_font_list(void)
2991 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2992 static const WCHAR pathW[] = {'P','a','t','h',0};
2994 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2995 WCHAR windowsdir[MAX_PATH];
2997 const char *data_dir;
2999 delete_external_font_keys();
3001 /* load the system bitmap fonts */
3002 load_system_fonts();
3004 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3005 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3006 strcatW(windowsdir, fontsW);
3007 if((unixname = wine_get_unix_file_name(windowsdir)))
3009 ReadFontDir(unixname, FALSE);
3010 HeapFree(GetProcessHeap(), 0, unixname);
3013 /* load the system truetype fonts */
3014 data_dir = wine_get_data_dir();
3015 if (!data_dir) data_dir = wine_get_build_dir();
3016 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3018 strcpy(unixname, data_dir);
3019 strcat(unixname, "/fonts/");
3020 ReadFontDir(unixname, TRUE);
3021 HeapFree(GetProcessHeap(), 0, unixname);
3024 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3025 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3026 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3028 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3029 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3030 &hkey) == ERROR_SUCCESS)
3032 LPWSTR data, valueW;
3033 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3034 &valuelen, &datalen, NULL, NULL);
3036 valuelen++; /* returned value doesn't include room for '\0' */
3037 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3038 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3041 dlen = datalen * sizeof(WCHAR);
3043 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3044 &dlen) == ERROR_SUCCESS)
3046 if(data[0] && (data[1] == ':'))
3048 if((unixname = wine_get_unix_file_name(data)))
3050 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3051 HeapFree(GetProcessHeap(), 0, unixname);
3054 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3056 WCHAR pathW[MAX_PATH];
3057 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3060 sprintfW(pathW, fmtW, windowsdir, data);
3061 if((unixname = wine_get_unix_file_name(pathW)))
3063 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3064 HeapFree(GetProcessHeap(), 0, unixname);
3067 load_font_from_data_dir(data);
3069 /* reset dlen and vlen */
3074 HeapFree(GetProcessHeap(), 0, data);
3075 HeapFree(GetProcessHeap(), 0, valueW);
3079 load_fontconfig_fonts();
3081 /* then look in any directories that we've specified in the config file */
3082 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3083 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3089 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3091 len += sizeof(WCHAR);
3092 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3093 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3095 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3096 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3097 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3098 TRACE( "got font path %s\n", debugstr_a(valueA) );
3102 LPSTR next = strchr( ptr, ':' );
3103 if (next) *next++ = 0;
3104 ReadFontDir( ptr, TRUE );
3107 HeapFree( GetProcessHeap(), 0, valueA );
3109 HeapFree( GetProcessHeap(), 0, valueW );
3115 static BOOL move_to_front(const WCHAR *name)
3117 Family *family, *cursor2;
3118 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3120 if(!strcmpiW(family->FamilyName, name))
3122 list_remove(&family->entry);
3123 list_add_head(&font_list, &family->entry);
3130 static BOOL set_default(const WCHAR **name_list)
3134 if (move_to_front(*name_list)) return TRUE;
3141 static void reorder_font_list(void)
3143 set_default( default_serif_list );
3144 set_default( default_fixed_list );
3145 set_default( default_sans_list );
3148 /*************************************************************
3151 * Initialize FreeType library and create a list of available faces
3153 BOOL WineEngInit(void)
3155 HKEY hkey_font_cache;
3159 /* update locale dependent font info in registry */
3162 if(!init_freetype()) return FALSE;
3164 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3166 ERR("Failed to create font mutex\n");
3169 WaitForSingleObject(font_mutex, INFINITE);
3171 create_font_cache_key(&hkey_font_cache, &disposition);
3173 if(disposition == REG_CREATED_NEW_KEY)
3176 load_font_list_from_cache(hkey_font_cache);
3178 RegCloseKey(hkey_font_cache);
3180 reorder_font_list();
3187 if(disposition == REG_CREATED_NEW_KEY)
3188 update_reg_entries();
3190 update_system_links();
3191 init_system_links();
3193 ReleaseMutex(font_mutex);
3198 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3201 TT_HoriHeader *pHori;
3205 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3206 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3208 if(height == 0) height = 16;
3210 /* Calc. height of EM square:
3212 * For +ve lfHeight we have
3213 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3214 * Re-arranging gives:
3215 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3217 * For -ve lfHeight we have
3219 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3220 * with il = winAscent + winDescent - units_per_em]
3225 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3226 ppem = MulDiv(ft_face->units_per_EM, height,
3227 pHori->Ascender - pHori->Descender);
3229 ppem = MulDiv(ft_face->units_per_EM, height,
3230 pOS2->usWinAscent + pOS2->usWinDescent);
3238 static struct font_mapping *map_font_file( const char *name )
3240 struct font_mapping *mapping;
3244 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3245 if (fstat( fd, &st ) == -1) goto error;
3247 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3249 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3251 mapping->refcount++;
3256 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3259 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3262 if (mapping->data == MAP_FAILED)
3264 HeapFree( GetProcessHeap(), 0, mapping );
3267 mapping->refcount = 1;
3268 mapping->dev = st.st_dev;
3269 mapping->ino = st.st_ino;
3270 mapping->size = st.st_size;
3271 list_add_tail( &mappings_list, &mapping->entry );
3279 static void unmap_font_file( struct font_mapping *mapping )
3281 if (!--mapping->refcount)
3283 list_remove( &mapping->entry );
3284 munmap( mapping->data, mapping->size );
3285 HeapFree( GetProcessHeap(), 0, mapping );
3289 static LONG load_VDMX(GdiFont*, LONG);
3291 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3298 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3302 if (!(font->mapping = map_font_file( face->file )))
3304 WARN("failed to map %s\n", debugstr_a(face->file));
3307 data_ptr = font->mapping->data;
3308 data_size = font->mapping->size;
3312 data_ptr = face->font_data_ptr;
3313 data_size = face->font_data_size;
3316 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3318 ERR("FT_New_Face rets %d\n", err);
3322 /* set it here, as load_VDMX needs it */
3323 font->ft_face = ft_face;
3325 if(FT_IS_SCALABLE(ft_face)) {
3326 /* load the VDMX table if we have one */
3327 font->ppem = load_VDMX(font, height);
3329 font->ppem = calc_ppem_for_height(ft_face, height);
3330 TRACE("height %d => ppem %d\n", height, font->ppem);
3332 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3333 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3335 font->ppem = height;
3336 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3337 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3343 static int get_nearest_charset(Face *face, int *cp)
3345 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3346 a single face with the requested charset. The idea is to check if
3347 the selected font supports the current ANSI codepage, if it does
3348 return the corresponding charset, else return the first charset */
3351 int acp = GetACP(), i;
3355 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3356 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3357 return csi.ciCharset;
3359 for(i = 0; i < 32; i++) {
3361 if(face->fs.fsCsb[0] & fs0) {
3362 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3364 return csi.ciCharset;
3367 FIXME("TCI failing on %x\n", fs0);
3371 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3372 face->fs.fsCsb[0], face->file);
3374 return DEFAULT_CHARSET;
3377 static GdiFont *alloc_font(void)
3379 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3381 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3382 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3384 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3385 ret->total_kern_pairs = (DWORD)-1;
3386 ret->kern_pairs = NULL;
3387 list_init(&ret->hfontlist);
3388 list_init(&ret->child_fonts);
3392 static void free_font(GdiFont *font)
3394 struct list *cursor, *cursor2;
3397 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3399 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3400 list_remove(cursor);
3402 free_font(child->font);
3403 HeapFree(GetProcessHeap(), 0, child);
3406 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3408 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3409 DeleteObject(hfontlist->hfont);
3410 list_remove(&hfontlist->entry);
3411 HeapFree(GetProcessHeap(), 0, hfontlist);
3414 if (font->ft_face) pFT_Done_Face(font->ft_face);
3415 if (font->mapping) unmap_font_file( font->mapping );
3416 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3417 HeapFree(GetProcessHeap(), 0, font->potm);
3418 HeapFree(GetProcessHeap(), 0, font->name);
3419 for (i = 0; i < font->gmsize; i++)
3420 HeapFree(GetProcessHeap(),0,font->gm[i]);
3421 HeapFree(GetProcessHeap(), 0, font->gm);
3422 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3423 HeapFree(GetProcessHeap(), 0, font);
3427 /*************************************************************
3430 * load the vdmx entry for the specified height
3433 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3434 ( ( (FT_ULong)_x4 << 24 ) | \
3435 ( (FT_ULong)_x3 << 16 ) | \
3436 ( (FT_ULong)_x2 << 8 ) | \
3439 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3454 static LONG load_VDMX(GdiFont *font, LONG height)
3458 BYTE devXRatio, devYRatio;
3459 USHORT numRecs, numRatios;
3460 DWORD result, offset = -1;
3464 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3466 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3469 /* FIXME: need the real device aspect ratio */
3473 numRecs = GET_BE_WORD(hdr[1]);
3474 numRatios = GET_BE_WORD(hdr[2]);
3476 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3477 for(i = 0; i < numRatios; i++) {
3480 offset = (3 * 2) + (i * sizeof(Ratios));
3481 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3484 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3486 if((ratio.xRatio == 0 &&
3487 ratio.yStartRatio == 0 &&
3488 ratio.yEndRatio == 0) ||
3489 (devXRatio == ratio.xRatio &&
3490 devYRatio >= ratio.yStartRatio &&
3491 devYRatio <= ratio.yEndRatio))
3493 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3494 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3495 offset = GET_BE_WORD(tmp);
3501 FIXME("No suitable ratio found\n");
3505 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3507 BYTE startsz, endsz;
3510 recs = GET_BE_WORD(group.recs);
3511 startsz = group.startsz;
3512 endsz = group.endsz;
3514 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3516 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3517 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3518 if(result == GDI_ERROR) {
3519 FIXME("Failed to retrieve vTable\n");
3524 for(i = 0; i < recs; i++) {
3525 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3526 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3527 ppem = GET_BE_WORD(vTable[i * 3]);
3529 if(yMax + -yMin == height) {
3532 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3535 if(yMax + -yMin > height) {
3538 goto end; /* failed */
3540 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3541 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3542 ppem = GET_BE_WORD(vTable[i * 3]);
3543 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3549 TRACE("ppem not found for height %d\n", height);
3553 HeapFree(GetProcessHeap(), 0, vTable);
3559 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3561 if(font->font_desc.hash != fd->hash) return TRUE;
3562 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3563 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3564 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3565 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3568 static void calc_hash(FONT_DESC *pfd)
3570 DWORD hash = 0, *ptr, two_chars;
3574 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3576 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3578 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3580 pwc = (WCHAR *)&two_chars;
3582 *pwc = toupperW(*pwc);
3584 *pwc = toupperW(*pwc);
3588 hash ^= !pfd->can_use_bitmap;
3593 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3598 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3602 fd.can_use_bitmap = can_use_bitmap;
3605 /* try the child list */
3606 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3607 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3608 if(!fontcmp(ret, &fd)) {
3609 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3610 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3611 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3612 if(hflist->hfont == hfont)
3618 /* try the in-use list */
3619 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3620 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3621 if(!fontcmp(ret, &fd)) {
3622 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3623 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3624 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3625 if(hflist->hfont == hfont)
3628 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3629 hflist->hfont = hfont;
3630 list_add_head(&ret->hfontlist, &hflist->entry);
3635 /* then the unused list */
3636 font_elem_ptr = list_head(&unused_gdi_font_list);
3637 while(font_elem_ptr) {
3638 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3639 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3640 if(!fontcmp(ret, &fd)) {
3641 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3642 assert(list_empty(&ret->hfontlist));
3643 TRACE("Found %p in unused list\n", ret);
3644 list_remove(&ret->entry);
3645 list_add_head(&gdi_font_list, &ret->entry);
3646 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3647 hflist->hfont = hfont;
3648 list_add_head(&ret->hfontlist, &hflist->entry);
3655 static void add_to_cache(GdiFont *font)
3657 static DWORD cache_num = 1;
3659 font->cache_num = cache_num++;
3660 list_add_head(&gdi_font_list, &font->entry);
3663 /*************************************************************
3664 * create_child_font_list
3666 static BOOL create_child_font_list(GdiFont *font)
3669 SYSTEM_LINKS *font_link;
3670 CHILD_FONT *font_link_entry, *new_child;
3674 psub = get_font_subst(&font_subst_list, font->name, -1);
3675 font_name = psub ? psub->to.name : font->name;
3676 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3678 if(!strcmpiW(font_link->font_name, font_name))
3680 TRACE("found entry in system list\n");
3681 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3683 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3684 new_child->face = font_link_entry->face;
3685 new_child->font = NULL;
3686 list_add_tail(&font->child_fonts, &new_child->entry);
3687 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3694 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3695 * Sans Serif. This is how asian windows get default fallbacks for fonts
3697 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3698 font->charset != OEM_CHARSET &&
3699 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3700 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3702 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3704 TRACE("found entry in default fallback list\n");
3705 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3707 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3708 new_child->face = font_link_entry->face;
3709 new_child->font = NULL;
3710 list_add_tail(&font->child_fonts, &new_child->entry);
3711 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3721 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3723 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3725 if (pFT_Set_Charmap)
3728 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3730 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3732 for (i = 0; i < ft_face->num_charmaps; i++)
3734 if (ft_face->charmaps[i]->encoding == encoding)
3736 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3737 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3739 switch (ft_face->charmaps[i]->platform_id)
3742 cmap_def = ft_face->charmaps[i];
3744 case 0: /* Apple Unicode */
3745 cmap0 = ft_face->charmaps[i];
3747 case 1: /* Macintosh */
3748 cmap1 = ft_face->charmaps[i];
3751 cmap2 = ft_face->charmaps[i];
3753 case 3: /* Microsoft */
3754 cmap3 = ft_face->charmaps[i];
3759 if (cmap3) /* prefer Microsoft cmap table */
3760 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3762 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3764 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3766 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3768 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3770 return ft_err == FT_Err_Ok;
3773 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3776 /*************************************************************
3777 * WineEngCreateFontInstance
3780 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3783 Face *face, *best, *best_bitmap;
3784 Family *family, *last_resort_family;
3785 struct list *family_elem_ptr, *face_elem_ptr;
3786 INT height, width = 0;
3787 unsigned int score = 0, new_score;
3788 signed int diff = 0, newdiff;
3789 BOOL bd, it, can_use_bitmap;
3794 FontSubst *psub = NULL;
3796 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3797 lf.lfWidth = abs(lf.lfWidth);
3799 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3801 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3802 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3803 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3806 if(dc->GraphicsMode == GM_ADVANCED)
3807 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3810 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3811 font scaling abilities. */
3812 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3813 dcmat.eM21 = dcmat.eM12 = 0;
3816 /* Try to avoid not necessary glyph transformations */
3817 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3819 lf.lfHeight *= fabs(dcmat.eM11);
3820 lf.lfWidth *= fabs(dcmat.eM11);
3821 dcmat.eM11 = dcmat.eM22 = 1.0;
3824 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3825 dcmat.eM21, dcmat.eM22);
3828 EnterCriticalSection( &freetype_cs );
3830 /* check the cache first */
3831 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3832 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3833 LeaveCriticalSection( &freetype_cs );
3837 TRACE("not in cache\n");
3838 if(list_empty(&font_list)) /* No fonts installed */
3840 TRACE("No fonts installed\n");
3841 LeaveCriticalSection( &freetype_cs );
3847 ret->font_desc.matrix = dcmat;
3848 ret->font_desc.lf = lf;
3849 ret->font_desc.can_use_bitmap = can_use_bitmap;
3850 calc_hash(&ret->font_desc);
3851 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3852 hflist->hfont = hfont;
3853 list_add_head(&ret->hfontlist, &hflist->entry);
3855 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3856 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3857 original value lfCharSet. Note this is a special case for
3858 Symbol and doesn't happen at least for "Wingdings*" */
3860 if(!strcmpiW(lf.lfFaceName, SymbolW))
3861 lf.lfCharSet = SYMBOL_CHARSET;
3863 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3864 switch(lf.lfCharSet) {
3865 case DEFAULT_CHARSET:
3866 csi.fs.fsCsb[0] = 0;
3869 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3870 csi.fs.fsCsb[0] = 0;
3876 if(lf.lfFaceName[0] != '\0') {
3877 SYSTEM_LINKS *font_link;
3878 CHILD_FONT *font_link_entry;
3879 LPWSTR FaceName = lf.lfFaceName;
3882 * Check for a leading '@' this signals that the font is being
3883 * requested in tategaki mode (vertical writing substitution) but
3884 * does not affect the fontface that is to be selected.
3886 if (lf.lfFaceName[0]=='@')
3887 FaceName = &lf.lfFaceName[1];
3889 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3892 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3893 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3894 if (psub->to.charset != -1)
3895 lf.lfCharSet = psub->to.charset;
3898 /* We want a match on name and charset or just name if
3899 charset was DEFAULT_CHARSET. If the latter then
3900 we fixup the returned charset later in get_nearest_charset
3901 where we'll either use the charset of the current ansi codepage
3902 or if that's unavailable the first charset that the font supports.
3904 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3905 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3906 if (!strcmpiW(family->FamilyName, FaceName) ||
3907 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3909 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3910 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3911 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3912 if(face->scalable || can_use_bitmap)
3918 /* Search by full face name. */
3919 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3920 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3921 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3922 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3923 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3924 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3926 if(face->scalable || can_use_bitmap)
3933 * Try check the SystemLink list first for a replacement font.
3934 * We may find good replacements there.
3936 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3938 if(!strcmpiW(font_link->font_name, FaceName) ||
3939 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3941 TRACE("found entry in system list\n");
3942 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3944 face = font_link_entry->face;
3945 family = face->family;
3946 if(csi.fs.fsCsb[0] &
3947 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3949 if(face->scalable || can_use_bitmap)
3957 psub = NULL; /* substitution is no more relevant */
3959 /* If requested charset was DEFAULT_CHARSET then try using charset
3960 corresponding to the current ansi codepage */
3961 if (!csi.fs.fsCsb[0])
3964 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3965 FIXME("TCI failed on codepage %d\n", acp);
3966 csi.fs.fsCsb[0] = 0;
3968 lf.lfCharSet = csi.ciCharset;
3971 /* Face families are in the top 4 bits of lfPitchAndFamily,
3972 so mask with 0xF0 before testing */
3974 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3975 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3976 strcpyW(lf.lfFaceName, defFixed);
3977 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3978 strcpyW(lf.lfFaceName, defSerif);
3979 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3980 strcpyW(lf.lfFaceName, defSans);
3982 strcpyW(lf.lfFaceName, defSans);
3983 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3984 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3985 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3986 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3987 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3988 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3989 if(face->scalable || can_use_bitmap)
3995 last_resort_family = NULL;
3996 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3997 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3998 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3999 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4000 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4003 if(can_use_bitmap && !last_resort_family)
4004 last_resort_family = family;
4009 if(last_resort_family) {
4010 family = last_resort_family;
4011 csi.fs.fsCsb[0] = 0;
4015 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4016 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4017 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4018 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4019 if(face->scalable) {
4020 csi.fs.fsCsb[0] = 0;
4021 WARN("just using first face for now\n");
4024 if(can_use_bitmap && !last_resort_family)
4025 last_resort_family = family;
4028 if(!last_resort_family) {
4029 FIXME("can't find a single appropriate font - bailing\n");
4031 LeaveCriticalSection( &freetype_cs );
4035 WARN("could only find a bitmap font - this will probably look awful!\n");
4036 family = last_resort_family;
4037 csi.fs.fsCsb[0] = 0;
4040 it = lf.lfItalic ? 1 : 0;
4041 bd = lf.lfWeight > 550 ? 1 : 0;
4043 height = lf.lfHeight;
4045 face = best = best_bitmap = NULL;
4046 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4048 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4052 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4053 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4054 new_score = (italic ^ it) + (bold ^ bd);
4055 if(!best || new_score <= score)
4057 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4058 italic, bold, it, bd);
4061 if(best->scalable && score == 0) break;
4065 newdiff = height - (signed int)(best->size.height);
4067 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4068 if(!best_bitmap || new_score < score ||
4069 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4071 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4074 if(score == 0 && diff == 0) break;
4081 face = best->scalable ? best : best_bitmap;
4082 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4083 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4086 height = lf.lfHeight;
4090 if(csi.fs.fsCsb[0]) {
4091 ret->charset = lf.lfCharSet;
4092 ret->codepage = csi.ciACP;
4095 ret->charset = get_nearest_charset(face, &ret->codepage);
4097 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4098 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4100 ret->aveWidth = height ? lf.lfWidth : 0;
4102 if(!face->scalable) {
4103 /* Windows uses integer scaling factors for bitmap fonts */
4104 INT scale, scaled_height;
4105 GdiFont *cachedfont;
4107 /* FIXME: rotation of bitmap fonts is ignored */
4108 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4110 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4111 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4112 dcmat.eM11 = dcmat.eM22 = 1.0;
4113 /* As we changed the matrix, we need to search the cache for the font again,
4114 * otherwise we might explode the cache. */
4115 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4116 TRACE("Found cached font after non-scalable matrix rescale!\n");
4118 LeaveCriticalSection( &freetype_cs );
4121 calc_hash(&ret->font_desc);
4123 if (height != 0) height = diff;
4124 height += face->size.height;
4126 scale = (height + face->size.height - 1) / face->size.height;
4127 scaled_height = scale * face->size.height;
4128 /* Only jump to the next height if the difference <= 25% original height */
4129 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4130 /* The jump between unscaled and doubled is delayed by 1 */
4131 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4132 ret->scale_y = scale;
4134 width = face->size.x_ppem >> 6;
4135 height = face->size.y_ppem >> 6;
4139 TRACE("font scale y: %f\n", ret->scale_y);
4141 ret->ft_face = OpenFontFace(ret, face, width, height);
4146 LeaveCriticalSection( &freetype_cs );
4150 ret->ntmFlags = face->ntmFlags;
4152 if (ret->charset == SYMBOL_CHARSET &&
4153 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4156 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4160 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4163 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4164 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4165 ret->underline = lf.lfUnderline ? 0xff : 0;
4166 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4167 create_child_font_list(ret);
4169 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
4171 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
4172 if (length != GDI_ERROR)
4174 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4175 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4176 TRACE("Loaded GSUB table of %i bytes\n",length);
4180 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4183 LeaveCriticalSection( &freetype_cs );
4187 static void dump_gdi_font_list(void)
4190 struct list *elem_ptr;
4192 TRACE("---------- gdiFont Cache ----------\n");
4193 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4194 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4195 TRACE("gdiFont=%p %s %d\n",
4196 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4199 TRACE("---------- Unused gdiFont Cache ----------\n");
4200 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4201 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4202 TRACE("gdiFont=%p %s %d\n",
4203 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4206 TRACE("---------- Child gdiFont Cache ----------\n");
4207 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4208 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4209 TRACE("gdiFont=%p %s %d\n",
4210 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4214 /*************************************************************
4215 * WineEngDestroyFontInstance
4217 * free the gdiFont associated with this handle
4220 BOOL WineEngDestroyFontInstance(HFONT handle)
4225 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4229 EnterCriticalSection( &freetype_cs );
4231 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4233 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4234 while(hfontlist_elem_ptr) {
4235 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4236 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4237 if(hflist->hfont == handle) {
4238 TRACE("removing child font %p from child list\n", gdiFont);
4239 list_remove(&gdiFont->entry);
4240 LeaveCriticalSection( &freetype_cs );
4246 TRACE("destroying hfont=%p\n", handle);
4248 dump_gdi_font_list();
4250 font_elem_ptr = list_head(&gdi_font_list);
4251 while(font_elem_ptr) {
4252 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4253 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4255 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4256 while(hfontlist_elem_ptr) {
4257 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4258 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4259 if(hflist->hfont == handle) {
4260 list_remove(&hflist->entry);
4261 HeapFree(GetProcessHeap(), 0, hflist);
4265 if(list_empty(&gdiFont->hfontlist)) {
4266 TRACE("Moving to Unused list\n");
4267 list_remove(&gdiFont->entry);
4268 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4273 font_elem_ptr = list_head(&unused_gdi_font_list);
4274 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4275 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4276 while(font_elem_ptr) {
4277 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4278 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4279 TRACE("freeing %p\n", gdiFont);
4280 list_remove(&gdiFont->entry);
4283 LeaveCriticalSection( &freetype_cs );
4287 /***************************************************
4288 * create_enum_charset_list
4290 * This function creates charset enumeration list because in DEFAULT_CHARSET
4291 * case, the ANSI codepage's charset takes precedence over other charsets.
4292 * This function works as a filter other than DEFAULT_CHARSET case.
4294 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4299 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4300 csi.fs.fsCsb[0] != 0) {
4301 list->element[n].mask = csi.fs.fsCsb[0];
4302 list->element[n].charset = csi.ciCharset;
4303 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4306 else { /* charset is DEFAULT_CHARSET or invalid. */
4309 /* Set the current codepage's charset as the first element. */
4311 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4312 csi.fs.fsCsb[0] != 0) {
4313 list->element[n].mask = csi.fs.fsCsb[0];
4314 list->element[n].charset = csi.ciCharset;
4315 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4319 /* Fill out left elements. */
4320 for (i = 0; i < 32; i++) {
4322 fs.fsCsb[0] = 1L << i;
4324 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4325 continue; /* skip, already added. */
4326 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4327 continue; /* skip, this is an invalid fsCsb bit. */
4329 list->element[n].mask = fs.fsCsb[0];
4330 list->element[n].charset = csi.ciCharset;
4331 list->element[n].name = ElfScriptsW[i];
4340 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4341 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4346 if (face->cached_enum_data)
4349 *pelf = face->cached_enum_data->elf;
4350 *pntm = face->cached_enum_data->ntm;
4351 *ptype = face->cached_enum_data->type;
4355 font = alloc_font();
4357 if(face->scalable) {
4358 height = -2048; /* 2048 is the most common em size */
4361 height = face->size.y_ppem >> 6;
4362 width = face->size.x_ppem >> 6;
4364 font->scale_y = 1.0;
4366 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4372 font->name = strdupW(face->family->FamilyName);
4373 font->ntmFlags = face->ntmFlags;
4375 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4377 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4379 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4381 lstrcpynW(pelf->elfLogFont.lfFaceName,
4382 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4384 lstrcpynW(pelf->elfFullName,
4385 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4387 lstrcpynW(pelf->elfStyle,
4388 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4393 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4395 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4397 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4399 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4401 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4402 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4405 pntm->ntmTm.ntmFlags = face->ntmFlags;
4406 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4407 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4408 pntm->ntmFontSig = face->fs;
4410 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4412 pelf->elfLogFont.lfEscapement = 0;
4413 pelf->elfLogFont.lfOrientation = 0;
4414 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4415 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4416 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4417 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4418 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4419 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4420 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4421 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4422 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4423 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4424 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4427 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4428 *ptype |= TRUETYPE_FONTTYPE;
4429 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4430 *ptype |= DEVICE_FONTTYPE;
4431 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4432 *ptype |= RASTER_FONTTYPE;
4434 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4435 if (face->cached_enum_data)
4437 face->cached_enum_data->elf = *pelf;
4438 face->cached_enum_data->ntm = *pntm;
4439 face->cached_enum_data->type = *ptype;
4445 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4447 struct list *face_elem_ptr;
4449 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4451 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4453 static const WCHAR spaceW[] = { ' ',0 };
4454 WCHAR full_family_name[LF_FULLFACESIZE];
4455 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4457 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4459 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4460 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4464 strcpyW(full_family_name, family->FamilyName);
4465 strcatW(full_family_name, spaceW);
4466 strcatW(full_family_name, face->StyleName);
4467 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4473 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4475 static const WCHAR spaceW[] = { ' ',0 };
4476 WCHAR full_family_name[LF_FULLFACESIZE];
4478 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4480 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4482 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4483 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4487 strcpyW(full_family_name, face->family->FamilyName);
4488 strcatW(full_family_name, spaceW);
4489 strcatW(full_family_name, face->StyleName);
4490 return !strcmpiW(lf->lfFaceName, full_family_name);
4493 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4494 FONTENUMPROCW proc, LPARAM lparam)
4497 NEWTEXTMETRICEXW ntm;
4501 GetEnumStructs(face, &elf, &ntm, &type);
4502 for(i = 0; i < list->total; i++) {
4503 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4504 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4505 strcpyW(elf.elfScript, OEM_DOSW);
4506 i = 32; /* break out of loop */
4507 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4510 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4511 if(list->element[i].name)
4512 strcpyW(elf.elfScript, list->element[i].name);
4514 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4516 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4517 debugstr_w(elf.elfLogFont.lfFaceName),
4518 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4519 list->element[i].charset, type, debugstr_w(elf.elfScript),
4520 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4521 ntm.ntmTm.ntmFlags);
4522 /* release section before callback (FIXME) */
4523 LeaveCriticalSection( &freetype_cs );
4524 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4525 EnterCriticalSection( &freetype_cs );
4530 /*************************************************************
4534 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4538 struct list *family_elem_ptr, *face_elem_ptr;
4540 struct enum_charset_list enum_charsets;
4544 lf.lfCharSet = DEFAULT_CHARSET;
4545 lf.lfPitchAndFamily = 0;
4546 lf.lfFaceName[0] = 0;
4550 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4552 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4555 EnterCriticalSection( &freetype_cs );
4556 if(plf->lfFaceName[0]) {
4558 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4561 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4562 debugstr_w(psub->to.name));
4564 strcpyW(lf.lfFaceName, psub->to.name);
4568 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4569 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4570 if(family_matches(family, plf)) {
4571 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4572 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4573 if (!face_matches(face, plf)) continue;
4574 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4579 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4580 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4581 face_elem_ptr = list_head(&family->faces);
4582 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4583 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4586 LeaveCriticalSection( &freetype_cs );
4590 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4592 pt->x.value = vec->x >> 6;
4593 pt->x.fract = (vec->x & 0x3f) << 10;
4594 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4595 pt->y.value = vec->y >> 6;
4596 pt->y.fract = (vec->y & 0x3f) << 10;
4597 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4601 /***************************************************
4602 * According to the MSDN documentation on WideCharToMultiByte,
4603 * certain codepages cannot set the default_used parameter.
4604 * This returns TRUE if the codepage can set that parameter, false else
4605 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4607 static BOOL codepage_sets_default_used(UINT codepage)
4621 * GSUB Table handling functions
4624 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4626 const GSUB_CoverageFormat1* cf1;
4630 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4632 int count = GET_BE_WORD(cf1->GlyphCount);
4634 TRACE("Coverage Format 1, %i glyphs\n",count);
4635 for (i = 0; i < count; i++)
4636 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4640 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4642 const GSUB_CoverageFormat2* cf2;
4645 cf2 = (const GSUB_CoverageFormat2*)cf1;
4647 count = GET_BE_WORD(cf2->RangeCount);
4648 TRACE("Coverage Format 2, %i ranges\n",count);
4649 for (i = 0; i < count; i++)
4651 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4653 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4654 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4656 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4657 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4663 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4668 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4670 const GSUB_ScriptList *script;
4671 const GSUB_Script *deflt = NULL;
4673 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4675 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4676 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4678 const GSUB_Script *scr;
4681 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4682 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4684 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4686 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4692 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4696 const GSUB_LangSys *Lang;
4698 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4700 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4702 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4703 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4705 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4708 offset = GET_BE_WORD(script->DefaultLangSys);
4711 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4717 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4720 const GSUB_FeatureList *feature;
4721 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4723 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4724 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4726 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4727 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4729 const GSUB_Feature *feat;
4730 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4737 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4741 const GSUB_LookupList *lookup;
4742 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4744 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4745 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4747 const GSUB_LookupTable *look;
4748 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4749 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4750 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4751 if (GET_BE_WORD(look->LookupType) != 1)
4752 FIXME("We only handle SubType 1\n");
4757 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4759 const GSUB_SingleSubstFormat1 *ssf1;
4760 offset = GET_BE_WORD(look->SubTable[j]);
4761 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4762 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4764 int offset = GET_BE_WORD(ssf1->Coverage);
4765 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4766 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4768 TRACE(" Glyph 0x%x ->",glyph);
4769 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4770 TRACE(" 0x%x\n",glyph);
4775 const GSUB_SingleSubstFormat2 *ssf2;
4779 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4780 offset = GET_BE_WORD(ssf1->Coverage);
4781 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4782 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4783 TRACE(" Coverage index %i\n",index);
4786 TRACE(" Glyph is 0x%x ->",glyph);
4787 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4788 TRACE("0x%x\n",glyph);
4797 static const char* get_opentype_script(const GdiFont *font)
4800 * I am not sure if this is the correct way to generate our script tag
4803 switch (font->charset)
4805 case ANSI_CHARSET: return "latn";
4806 case BALTIC_CHARSET: return "latn"; /* ?? */
4807 case CHINESEBIG5_CHARSET: return "hani";
4808 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4809 case GB2312_CHARSET: return "hani";
4810 case GREEK_CHARSET: return "grek";
4811 case HANGUL_CHARSET: return "hang";
4812 case RUSSIAN_CHARSET: return "cyrl";
4813 case SHIFTJIS_CHARSET: return "kana";
4814 case TURKISH_CHARSET: return "latn"; /* ?? */
4815 case VIETNAMESE_CHARSET: return "latn";
4816 case JOHAB_CHARSET: return "latn"; /* ?? */
4817 case ARABIC_CHARSET: return "arab";
4818 case HEBREW_CHARSET: return "hebr";
4819 case THAI_CHARSET: return "thai";
4820 default: return "latn";
4824 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4826 const GSUB_Header *header;
4827 const GSUB_Script *script;
4828 const GSUB_LangSys *language;
4829 const GSUB_Feature *feature;
4831 if (!font->GSUB_Table)
4834 header = font->GSUB_Table;
4836 script = GSUB_get_script_table(header, get_opentype_script(font));
4839 TRACE("Script not found\n");
4842 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4845 TRACE("Language not found\n");
4848 feature = GSUB_get_feature(header, language, "vrt2");
4850 feature = GSUB_get_feature(header, language, "vert");
4853 TRACE("vrt2/vert feature not found\n");
4856 return GSUB_apply_feature(header, feature, glyph);
4859 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4863 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4864 WCHAR wc = (WCHAR)glyph;
4866 BOOL *default_used_pointer;
4869 default_used_pointer = NULL;
4870 default_used = FALSE;
4871 if (codepage_sets_default_used(font->codepage))
4872 default_used_pointer = &default_used;
4873 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4876 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4877 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4878 return get_GSUB_vert_glyph(font,ret);
4881 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4883 if (glyph < 0x100) glyph += 0xf000;
4884 /* there is a number of old pre-Unicode "broken" TTFs, which
4885 do have symbols at U+00XX instead of U+f0XX */
4886 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4887 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4889 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4891 return get_GSUB_vert_glyph(font,glyphId);
4894 /*************************************************************
4895 * WineEngGetGlyphIndices
4898 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4899 LPWORD pgi, DWORD flags)
4903 BOOL got_default = FALSE;
4905 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4907 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4911 for(i = 0; i < count; i++)
4913 pgi[i] = get_glyph_index(font, lpstr[i]);
4918 if (FT_IS_SFNT(font->ft_face))
4920 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4921 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4926 WineEngGetTextMetrics(font, &textm);
4927 default_char = textm.tmDefaultChar;
4931 pgi[i] = default_char;
4937 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4939 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4940 return !memcmp(matrix, &identity, sizeof(FMAT2));
4943 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4945 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4946 return !memcmp(matrix, &identity, sizeof(MAT2));
4949 /*************************************************************
4950 * WineEngGetGlyphOutline
4952 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4953 * except that the first parameter is the HWINEENGFONT of the font in
4954 * question rather than an HDC.
4957 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4958 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4961 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4962 FT_Face ft_face = incoming_font->ft_face;
4963 GdiFont *font = incoming_font;
4964 FT_UInt glyph_index;
4965 DWORD width, height, pitch, needed = 0;
4966 FT_Bitmap ft_bitmap;
4968 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4970 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4971 double widthRatio = 1.0;
4972 FT_Matrix transMat = identityMat;
4973 FT_Matrix transMatUnrotated;
4974 BOOL needsTransform = FALSE;
4975 BOOL tategaki = (font->GSUB_Table != NULL);
4976 UINT original_index;
4978 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4979 buflen, buf, lpmat);
4981 TRACE("font transform %f %f %f %f\n",
4982 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4983 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4986 EnterCriticalSection( &freetype_cs );
4988 if(format & GGO_GLYPH_INDEX) {
4989 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4990 original_index = glyph;
4991 format &= ~GGO_GLYPH_INDEX;
4993 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4994 ft_face = font->ft_face;
4995 original_index = glyph_index;
4998 if(format & GGO_UNHINTED) {
4999 load_flags |= FT_LOAD_NO_HINTING;
5000 format &= ~GGO_UNHINTED;
5003 /* tategaki never appears to happen to lower glyph index */
5004 if (glyph_index < TATEGAKI_LOWER_BOUND )
5007 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5008 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5009 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5010 font->gmsize * sizeof(GM*));
5012 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5013 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5015 *lpgm = FONT_GM(font,original_index)->gm;
5016 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5017 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5018 lpgm->gmCellIncX, lpgm->gmCellIncY);
5019 LeaveCriticalSection( &freetype_cs );
5020 return 1; /* FIXME */
5024 if (!font->gm[original_index / GM_BLOCK_SIZE])
5025 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5027 /* Scaling factor */
5032 WineEngGetTextMetrics(font, &tm);
5034 widthRatio = (double)font->aveWidth;
5035 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5038 widthRatio = font->scale_y;
5040 /* Scaling transform */
5041 if (widthRatio != 1.0 || font->scale_y != 1.0)
5044 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5047 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5049 pFT_Matrix_Multiply(&scaleMat, &transMat);
5050 needsTransform = TRUE;
5053 /* Slant transform */
5054 if (font->fake_italic) {
5057 slantMat.xx = (1 << 16);
5058 slantMat.xy = ((1 << 16) >> 2);
5060 slantMat.yy = (1 << 16);
5061 pFT_Matrix_Multiply(&slantMat, &transMat);
5062 needsTransform = TRUE;
5065 /* Rotation transform */
5066 transMatUnrotated = transMat;
5067 if(font->orientation && !tategaki) {
5068 FT_Matrix rotationMat;
5070 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5071 pFT_Vector_Unit(&vecAngle, angle);
5072 rotationMat.xx = vecAngle.x;
5073 rotationMat.xy = -vecAngle.y;
5074 rotationMat.yx = -rotationMat.xy;
5075 rotationMat.yy = rotationMat.xx;
5077 pFT_Matrix_Multiply(&rotationMat, &transMat);
5078 needsTransform = TRUE;
5081 /* World transform */
5082 if (!is_identity_FMAT2(&font->font_desc.matrix))
5085 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5086 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5087 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5088 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5089 pFT_Matrix_Multiply(&worldMat, &transMat);
5090 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5091 needsTransform = TRUE;
5094 /* Extra transformation specified by caller */
5095 if (!is_identity_MAT2(lpmat))
5098 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5099 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5100 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5101 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5102 pFT_Matrix_Multiply(&extraMat, &transMat);
5103 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5104 needsTransform = TRUE;
5107 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5108 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5109 format == GGO_GRAY8_BITMAP))
5111 load_flags |= FT_LOAD_NO_BITMAP;
5114 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5117 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5118 LeaveCriticalSection( &freetype_cs );
5122 if(!needsTransform) {
5123 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5124 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5125 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5127 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5128 bottom = (ft_face->glyph->metrics.horiBearingY -
5129 ft_face->glyph->metrics.height) & -64;
5130 lpgm->gmCellIncX = adv;
5131 lpgm->gmCellIncY = 0;
5138 for(xc = 0; xc < 2; xc++) {
5139 for(yc = 0; yc < 2; yc++) {
5140 vec.x = (ft_face->glyph->metrics.horiBearingX +
5141 xc * ft_face->glyph->metrics.width);
5142 vec.y = ft_face->glyph->metrics.horiBearingY -
5143 yc * ft_face->glyph->metrics.height;
5144 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5145 pFT_Vector_Transform(&vec, &transMat);
5146 if(xc == 0 && yc == 0) {
5147 left = right = vec.x;
5148 top = bottom = vec.y;
5150 if(vec.x < left) left = vec.x;
5151 else if(vec.x > right) right = vec.x;
5152 if(vec.y < bottom) bottom = vec.y;
5153 else if(vec.y > top) top = vec.y;
5158 right = (right + 63) & -64;
5159 bottom = bottom & -64;
5160 top = (top + 63) & -64;
5162 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5163 vec.x = ft_face->glyph->metrics.horiAdvance;
5165 pFT_Vector_Transform(&vec, &transMat);
5166 lpgm->gmCellIncX = (vec.x+63) >> 6;
5167 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5169 vec.x = ft_face->glyph->metrics.horiAdvance;
5171 pFT_Vector_Transform(&vec, &transMatUnrotated);
5172 adv = (vec.x+63) >> 6;
5176 bbx = (right - left) >> 6;
5177 lpgm->gmBlackBoxX = (right - left) >> 6;
5178 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5179 lpgm->gmptGlyphOrigin.x = left >> 6;
5180 lpgm->gmptGlyphOrigin.y = top >> 6;
5182 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5183 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5184 lpgm->gmCellIncX, lpgm->gmCellIncY);
5186 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5187 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5189 FONT_GM(font,original_index)->gm = *lpgm;
5190 FONT_GM(font,original_index)->adv = adv;
5191 FONT_GM(font,original_index)->lsb = lsb;
5192 FONT_GM(font,original_index)->bbx = bbx;
5193 FONT_GM(font,original_index)->init = TRUE;
5196 if(format == GGO_METRICS)
5198 LeaveCriticalSection( &freetype_cs );
5199 return 1; /* FIXME */
5202 if(ft_face->glyph->format != ft_glyph_format_outline &&
5203 (format == GGO_NATIVE || format == GGO_BEZIER ||
5204 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5205 format == GGO_GRAY8_BITMAP))
5207 TRACE("loaded a bitmap\n");
5208 LeaveCriticalSection( &freetype_cs );
5214 width = lpgm->gmBlackBoxX;
5215 height = lpgm->gmBlackBoxY;
5216 pitch = ((width + 31) >> 5) << 2;
5217 needed = pitch * height;
5219 if(!buf || !buflen) break;
5221 switch(ft_face->glyph->format) {
5222 case ft_glyph_format_bitmap:
5224 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5225 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5226 INT h = ft_face->glyph->bitmap.rows;
5228 memcpy(dst, src, w);
5229 src += ft_face->glyph->bitmap.pitch;
5235 case ft_glyph_format_outline:
5236 ft_bitmap.width = width;
5237 ft_bitmap.rows = height;
5238 ft_bitmap.pitch = pitch;
5239 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5240 ft_bitmap.buffer = buf;
5243 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5245 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5247 /* Note: FreeType will only set 'black' bits for us. */
5248 memset(buf, 0, needed);
5249 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5253 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5254 LeaveCriticalSection( &freetype_cs );
5259 case GGO_GRAY2_BITMAP:
5260 case GGO_GRAY4_BITMAP:
5261 case GGO_GRAY8_BITMAP:
5262 case WINE_GGO_GRAY16_BITMAP:
5264 unsigned int mult, row, col;
5267 width = lpgm->gmBlackBoxX;
5268 height = lpgm->gmBlackBoxY;
5269 pitch = (width + 3) / 4 * 4;
5270 needed = pitch * height;
5272 if(!buf || !buflen) break;
5274 switch(ft_face->glyph->format) {
5275 case ft_glyph_format_bitmap:
5277 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5278 INT h = ft_face->glyph->bitmap.rows;
5280 memset( buf, 0, needed );
5282 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5283 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
5284 src += ft_face->glyph->bitmap.pitch;
5287 LeaveCriticalSection( &freetype_cs );
5290 case ft_glyph_format_outline:
5292 ft_bitmap.width = width;
5293 ft_bitmap.rows = height;
5294 ft_bitmap.pitch = pitch;
5295 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5296 ft_bitmap.buffer = buf;
5299 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5301 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5303 memset(ft_bitmap.buffer, 0, buflen);
5305 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5307 if(format == GGO_GRAY2_BITMAP)
5309 else if(format == GGO_GRAY4_BITMAP)
5311 else if(format == GGO_GRAY8_BITMAP)
5313 else /* format == WINE_GGO_GRAY16_BITMAP */
5315 LeaveCriticalSection( &freetype_cs );
5321 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5322 LeaveCriticalSection( &freetype_cs );
5327 for(row = 0; row < height; row++) {
5329 for(col = 0; col < width; col++, ptr++) {
5330 *ptr = (((int)*ptr) * mult + 128) / 256;
5337 case WINE_GGO_HRGB_BITMAP:
5338 case WINE_GGO_HBGR_BITMAP:
5339 case WINE_GGO_VRGB_BITMAP:
5340 case WINE_GGO_VBGR_BITMAP:
5341 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5343 switch (ft_face->glyph->format)
5345 case FT_GLYPH_FORMAT_BITMAP:
5350 width = lpgm->gmBlackBoxX;
5351 height = lpgm->gmBlackBoxY;
5353 needed = pitch * height;
5355 if (!buf || !buflen) break;
5357 memset(buf, 0, buflen);
5359 src = ft_face->glyph->bitmap.buffer;
5360 src_pitch = ft_face->glyph->bitmap.pitch;
5362 height = min( height, ft_face->glyph->bitmap.rows );
5365 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5367 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5368 ((unsigned int *)dst)[x] = ~0u;
5377 case FT_GLYPH_FORMAT_OUTLINE:
5381 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5382 INT x_shift, y_shift;
5384 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5385 FT_Render_Mode render_mode =
5386 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5387 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5389 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5391 if ( render_mode == FT_RENDER_MODE_LCD)
5393 lpgm->gmBlackBoxX += 2;
5394 lpgm->gmptGlyphOrigin.x -= 1;
5398 lpgm->gmBlackBoxY += 2;
5399 lpgm->gmptGlyphOrigin.y += 1;
5403 width = lpgm->gmBlackBoxX;
5404 height = lpgm->gmBlackBoxY;
5406 needed = pitch * height;
5408 if (!buf || !buflen) break;
5410 memset(buf, 0, buflen);
5412 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5414 if ( needsTransform )
5415 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5417 if ( pFT_Library_SetLcdFilter )
5418 pFT_Library_SetLcdFilter( library, lcdfilter );
5419 pFT_Render_Glyph (ft_face->glyph, render_mode);
5421 src = ft_face->glyph->bitmap.buffer;
5422 src_pitch = ft_face->glyph->bitmap.pitch;
5423 src_width = ft_face->glyph->bitmap.width;
5424 src_height = ft_face->glyph->bitmap.rows;
5426 if ( render_mode == FT_RENDER_MODE_LCD)
5434 rgb_interval = src_pitch;
5439 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5440 if ( x_shift < 0 ) x_shift = 0;
5441 if ( x_shift + (src_width / hmul) > width )
5442 x_shift = width - (src_width / hmul);
5444 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5445 if ( y_shift < 0 ) y_shift = 0;
5446 if ( y_shift + (src_height / vmul) > height )
5447 y_shift = height - (src_height / vmul);
5449 dst += x_shift + y_shift * ( pitch / 4 );
5450 while ( src_height )
5452 for ( x = 0; x < src_width / hmul; x++ )
5456 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5457 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5458 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5459 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5463 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5464 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5465 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5466 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5469 src += src_pitch * vmul;
5478 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5479 LeaveCriticalSection ( &freetype_cs );
5486 LeaveCriticalSection( &freetype_cs );
5492 int contour, point = 0, first_pt;
5493 FT_Outline *outline = &ft_face->glyph->outline;
5494 TTPOLYGONHEADER *pph;
5496 DWORD pph_start, cpfx, type;
5498 if(buflen == 0) buf = NULL;
5500 if (needsTransform && buf) {
5501 pFT_Outline_Transform(outline, &transMat);
5504 for(contour = 0; contour < outline->n_contours; contour++) {
5506 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5509 pph->dwType = TT_POLYGON_TYPE;
5510 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5512 needed += sizeof(*pph);
5514 while(point <= outline->contours[contour]) {
5515 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5516 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5517 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5521 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5524 } while(point <= outline->contours[contour] &&
5525 (outline->tags[point] & FT_Curve_Tag_On) ==
5526 (outline->tags[point-1] & FT_Curve_Tag_On));
5527 /* At the end of a contour Windows adds the start point, but
5529 if(point > outline->contours[contour] &&
5530 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5532 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5534 } else if(point <= outline->contours[contour] &&
5535 outline->tags[point] & FT_Curve_Tag_On) {
5536 /* add closing pt for bezier */
5538 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5546 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5549 pph->cb = needed - pph_start;
5555 /* Convert the quadratic Beziers to cubic Beziers.
5556 The parametric eqn for a cubic Bezier is, from PLRM:
5557 r(t) = at^3 + bt^2 + ct + r0
5558 with the control points:
5563 A quadratic Bezier has the form:
5564 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5566 So equating powers of t leads to:
5567 r1 = 2/3 p1 + 1/3 p0
5568 r2 = 2/3 p1 + 1/3 p2
5569 and of course r0 = p0, r3 = p2
5572 int contour, point = 0, first_pt;
5573 FT_Outline *outline = &ft_face->glyph->outline;
5574 TTPOLYGONHEADER *pph;
5576 DWORD pph_start, cpfx, type;
5577 FT_Vector cubic_control[4];
5578 if(buflen == 0) buf = NULL;
5580 if (needsTransform && buf) {
5581 pFT_Outline_Transform(outline, &transMat);
5584 for(contour = 0; contour < outline->n_contours; contour++) {
5586 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5589 pph->dwType = TT_POLYGON_TYPE;
5590 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5592 needed += sizeof(*pph);
5594 while(point <= outline->contours[contour]) {
5595 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5596 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5597 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5600 if(type == TT_PRIM_LINE) {
5602 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5606 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5609 /* FIXME: Possible optimization in endpoint calculation
5610 if there are two consecutive curves */
5611 cubic_control[0] = outline->points[point-1];
5612 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5613 cubic_control[0].x += outline->points[point].x + 1;
5614 cubic_control[0].y += outline->points[point].y + 1;
5615 cubic_control[0].x >>= 1;
5616 cubic_control[0].y >>= 1;
5618 if(point+1 > outline->contours[contour])
5619 cubic_control[3] = outline->points[first_pt];
5621 cubic_control[3] = outline->points[point+1];
5622 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5623 cubic_control[3].x += outline->points[point].x + 1;
5624 cubic_control[3].y += outline->points[point].y + 1;
5625 cubic_control[3].x >>= 1;
5626 cubic_control[3].y >>= 1;
5629 /* r1 = 1/3 p0 + 2/3 p1
5630 r2 = 1/3 p2 + 2/3 p1 */
5631 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5632 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5633 cubic_control[2] = cubic_control[1];
5634 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5635 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5636 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5637 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5639 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5640 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5641 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5646 } while(point <= outline->contours[contour] &&
5647 (outline->tags[point] & FT_Curve_Tag_On) ==
5648 (outline->tags[point-1] & FT_Curve_Tag_On));
5649 /* At the end of a contour Windows adds the start point,
5650 but only for Beziers and we've already done that.
5652 if(point <= outline->contours[contour] &&
5653 outline->tags[point] & FT_Curve_Tag_On) {
5654 /* This is the closing pt of a bezier, but we've already
5655 added it, so just inc point and carry on */
5662 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5665 pph->cb = needed - pph_start;
5671 FIXME("Unsupported format %d\n", format);
5672 LeaveCriticalSection( &freetype_cs );
5675 LeaveCriticalSection( &freetype_cs );
5679 static BOOL get_bitmap_text_metrics(GdiFont *font)
5681 FT_Face ft_face = font->ft_face;
5682 FT_WinFNT_HeaderRec winfnt_header;
5683 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5684 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5685 font->potm->otmSize = size;
5687 #define TM font->potm->otmTextMetrics
5688 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5690 TM.tmHeight = winfnt_header.pixel_height;
5691 TM.tmAscent = winfnt_header.ascent;
5692 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5693 TM.tmInternalLeading = winfnt_header.internal_leading;
5694 TM.tmExternalLeading = winfnt_header.external_leading;
5695 TM.tmAveCharWidth = winfnt_header.avg_width;
5696 TM.tmMaxCharWidth = winfnt_header.max_width;
5697 TM.tmWeight = winfnt_header.weight;
5699 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5700 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5701 TM.tmFirstChar = winfnt_header.first_char;
5702 TM.tmLastChar = winfnt_header.last_char;
5703 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5704 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5705 TM.tmItalic = winfnt_header.italic;
5706 TM.tmUnderlined = font->underline;
5707 TM.tmStruckOut = font->strikeout;
5708 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5709 TM.tmCharSet = winfnt_header.charset;
5713 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5714 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5715 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5716 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5717 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5718 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5719 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5720 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5722 TM.tmDigitizedAspectX = 96; /* FIXME */
5723 TM.tmDigitizedAspectY = 96; /* FIXME */
5725 TM.tmLastChar = 255;
5726 TM.tmDefaultChar = 32;
5727 TM.tmBreakChar = 32;
5728 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5729 TM.tmUnderlined = font->underline;
5730 TM.tmStruckOut = font->strikeout;
5731 /* NB inverted meaning of TMPF_FIXED_PITCH */
5732 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5733 TM.tmCharSet = font->charset;
5741 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5743 double scale_x, scale_y;
5747 scale_x = (double)font->aveWidth;
5748 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5751 scale_x = font->scale_y;
5753 scale_x *= fabs(font->font_desc.matrix.eM11);
5754 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5756 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5757 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5759 SCALE_Y(ptm->tmHeight);
5760 SCALE_Y(ptm->tmAscent);
5761 SCALE_Y(ptm->tmDescent);
5762 SCALE_Y(ptm->tmInternalLeading);
5763 SCALE_Y(ptm->tmExternalLeading);
5764 SCALE_Y(ptm->tmOverhang);
5766 SCALE_X(ptm->tmAveCharWidth);
5767 SCALE_X(ptm->tmMaxCharWidth);
5773 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5775 double scale_x, scale_y;
5779 scale_x = (double)font->aveWidth;
5780 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5783 scale_x = font->scale_y;
5785 scale_x *= fabs(font->font_desc.matrix.eM11);
5786 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5788 scale_font_metrics(font, &potm->otmTextMetrics);
5790 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5791 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5793 SCALE_Y(potm->otmAscent);
5794 SCALE_Y(potm->otmDescent);
5795 SCALE_Y(potm->otmLineGap);
5796 SCALE_Y(potm->otmsCapEmHeight);
5797 SCALE_Y(potm->otmsXHeight);
5798 SCALE_Y(potm->otmrcFontBox.top);
5799 SCALE_Y(potm->otmrcFontBox.bottom);
5800 SCALE_X(potm->otmrcFontBox.left);
5801 SCALE_X(potm->otmrcFontBox.right);
5802 SCALE_Y(potm->otmMacAscent);
5803 SCALE_Y(potm->otmMacDescent);
5804 SCALE_Y(potm->otmMacLineGap);
5805 SCALE_X(potm->otmptSubscriptSize.x);
5806 SCALE_Y(potm->otmptSubscriptSize.y);
5807 SCALE_X(potm->otmptSubscriptOffset.x);
5808 SCALE_Y(potm->otmptSubscriptOffset.y);
5809 SCALE_X(potm->otmptSuperscriptSize.x);
5810 SCALE_Y(potm->otmptSuperscriptSize.y);
5811 SCALE_X(potm->otmptSuperscriptOffset.x);
5812 SCALE_Y(potm->otmptSuperscriptOffset.y);
5813 SCALE_Y(potm->otmsStrikeoutSize);
5814 SCALE_Y(potm->otmsStrikeoutPosition);
5815 SCALE_Y(potm->otmsUnderscoreSize);
5816 SCALE_Y(potm->otmsUnderscorePosition);
5822 /*************************************************************
5823 * WineEngGetTextMetrics
5826 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5829 EnterCriticalSection( &freetype_cs );
5831 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5832 if(!get_bitmap_text_metrics(font))
5834 LeaveCriticalSection( &freetype_cs );
5838 /* Make sure that the font has sane width/height ratio */
5841 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5843 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5849 *ptm = font->potm->otmTextMetrics;
5850 scale_font_metrics(font, ptm);
5851 LeaveCriticalSection( &freetype_cs );
5855 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5859 for(i = 0; i < ft_face->num_charmaps; i++)
5861 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5867 /*************************************************************
5868 * WineEngGetOutlineTextMetrics
5871 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5872 OUTLINETEXTMETRICW *potm)
5874 FT_Face ft_face = font->ft_face;
5875 UINT needed, lenfam, lensty, ret;
5877 TT_HoriHeader *pHori;
5878 TT_Postscript *pPost;
5879 FT_Fixed x_scale, y_scale;
5880 WCHAR *family_nameW, *style_nameW;
5881 static const WCHAR spaceW[] = {' ', '\0'};
5883 INT ascent, descent;
5885 TRACE("font=%p\n", font);
5887 if(!FT_IS_SCALABLE(ft_face))
5891 EnterCriticalSection( &freetype_cs );
5894 if(cbSize >= font->potm->otmSize)
5896 memcpy(potm, font->potm, font->potm->otmSize);
5897 scale_outline_font_metrics(font, potm);
5899 LeaveCriticalSection( &freetype_cs );
5900 return font->potm->otmSize;
5904 needed = sizeof(*potm);
5906 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5907 family_nameW = strdupW(font->name);
5909 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5911 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5912 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5913 style_nameW, lensty/sizeof(WCHAR));
5915 /* These names should be read from the TT name table */
5917 /* length of otmpFamilyName */
5920 /* length of otmpFaceName */
5921 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5922 needed += lenfam; /* just the family name */
5924 needed += lenfam + lensty; /* family + " " + style */
5927 /* length of otmpStyleName */
5930 /* length of otmpFullName */
5931 needed += lenfam + lensty;
5934 x_scale = ft_face->size->metrics.x_scale;
5935 y_scale = ft_face->size->metrics.y_scale;
5937 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5939 FIXME("Can't find OS/2 table - not TT font?\n");
5944 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5946 FIXME("Can't find HHEA table - not TT font?\n");
5951 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5953 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",
5954 pOS2->usWinAscent, pOS2->usWinDescent,
5955 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5956 ft_face->ascender, ft_face->descender, ft_face->height,
5957 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5958 ft_face->bbox.yMax, ft_face->bbox.yMin);
5960 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5961 font->potm->otmSize = needed;
5963 #define TM font->potm->otmTextMetrics
5965 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5966 ascent = pHori->Ascender;
5967 descent = -pHori->Descender;
5969 ascent = pOS2->usWinAscent;
5970 descent = pOS2->usWinDescent;
5974 TM.tmAscent = font->yMax;
5975 TM.tmDescent = -font->yMin;
5976 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5978 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5979 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5980 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5981 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5984 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5987 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5989 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5990 ((ascent + descent) -
5991 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5993 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5994 if (TM.tmAveCharWidth == 0) {
5995 TM.tmAveCharWidth = 1;
5997 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5998 TM.tmWeight = FW_REGULAR;
5999 if (font->fake_bold)
6000 TM.tmWeight = FW_BOLD;
6003 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6005 if (pOS2->usWeightClass > FW_MEDIUM)
6006 TM.tmWeight = pOS2->usWeightClass;
6008 else if (pOS2->usWeightClass <= FW_MEDIUM)
6009 TM.tmWeight = pOS2->usWeightClass;
6012 TM.tmDigitizedAspectX = 300;
6013 TM.tmDigitizedAspectY = 300;
6014 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6015 * symbol range to 0 - f0ff
6018 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6023 case 1257: /* Baltic */
6024 TM.tmLastChar = 0xf8fd;
6027 TM.tmLastChar = 0xf0ff;
6029 TM.tmBreakChar = 0x20;
6030 TM.tmDefaultChar = 0x1f;
6034 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6035 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6037 if(pOS2->usFirstCharIndex <= 1)
6038 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6039 else if (pOS2->usFirstCharIndex > 0xff)
6040 TM.tmBreakChar = 0x20;
6042 TM.tmBreakChar = pOS2->usFirstCharIndex;
6043 TM.tmDefaultChar = TM.tmBreakChar - 1;
6045 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6046 TM.tmUnderlined = font->underline;
6047 TM.tmStruckOut = font->strikeout;
6049 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6050 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6051 (pOS2->version == 0xFFFFU ||
6052 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6053 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6055 TM.tmPitchAndFamily = 0;
6057 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6059 case PAN_FAMILY_SCRIPT:
6060 TM.tmPitchAndFamily |= FF_SCRIPT;
6063 case PAN_FAMILY_DECORATIVE:
6064 TM.tmPitchAndFamily |= FF_DECORATIVE;
6069 case PAN_FAMILY_TEXT_DISPLAY:
6070 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6071 /* which is clearly not what the panose spec says. */
6073 if(TM.tmPitchAndFamily == 0 || /* fixed */
6074 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6075 TM.tmPitchAndFamily = FF_MODERN;
6078 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6083 TM.tmPitchAndFamily |= FF_DONTCARE;
6086 case PAN_SERIF_COVE:
6087 case PAN_SERIF_OBTUSE_COVE:
6088 case PAN_SERIF_SQUARE_COVE:
6089 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6090 case PAN_SERIF_SQUARE:
6091 case PAN_SERIF_THIN:
6092 case PAN_SERIF_BONE:
6093 case PAN_SERIF_EXAGGERATED:
6094 case PAN_SERIF_TRIANGLE:
6095 TM.tmPitchAndFamily |= FF_ROMAN;
6098 case PAN_SERIF_NORMAL_SANS:
6099 case PAN_SERIF_OBTUSE_SANS:
6100 case PAN_SERIF_PERP_SANS:
6101 case PAN_SERIF_FLARED:
6102 case PAN_SERIF_ROUNDED:
6103 TM.tmPitchAndFamily |= FF_SWISS;
6110 if(FT_IS_SCALABLE(ft_face))
6111 TM.tmPitchAndFamily |= TMPF_VECTOR;
6113 if(FT_IS_SFNT(ft_face))
6115 if (font->ntmFlags & NTM_PS_OPENTYPE)
6116 TM.tmPitchAndFamily |= TMPF_DEVICE;
6118 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6121 TM.tmCharSet = font->charset;
6123 font->potm->otmFiller = 0;
6124 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6125 font->potm->otmfsSelection = pOS2->fsSelection;
6126 font->potm->otmfsType = pOS2->fsType;
6127 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6128 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6129 font->potm->otmItalicAngle = 0; /* POST table */
6130 font->potm->otmEMSquare = ft_face->units_per_EM;
6131 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6132 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6133 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6134 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6135 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6136 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6137 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6138 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6139 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6140 font->potm->otmMacAscent = TM.tmAscent;
6141 font->potm->otmMacDescent = -TM.tmDescent;
6142 font->potm->otmMacLineGap = font->potm->otmLineGap;
6143 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6144 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6145 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6146 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6147 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6148 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6149 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6150 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6151 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6152 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6153 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6155 font->potm->otmsUnderscoreSize = 0;
6156 font->potm->otmsUnderscorePosition = 0;
6158 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6159 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6163 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6164 cp = (char*)font->potm + sizeof(*font->potm);
6165 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6166 strcpyW((WCHAR*)cp, family_nameW);
6168 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6169 strcpyW((WCHAR*)cp, style_nameW);
6171 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6172 strcpyW((WCHAR*)cp, family_nameW);
6173 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6174 strcatW((WCHAR*)cp, spaceW);
6175 strcatW((WCHAR*)cp, style_nameW);
6176 cp += lenfam + lensty;
6179 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6180 strcpyW((WCHAR*)cp, family_nameW);
6181 strcatW((WCHAR*)cp, spaceW);
6182 strcatW((WCHAR*)cp, style_nameW);
6185 if(potm && needed <= cbSize)
6187 memcpy(potm, font->potm, font->potm->otmSize);
6188 scale_outline_font_metrics(font, potm);
6192 HeapFree(GetProcessHeap(), 0, style_nameW);
6193 HeapFree(GetProcessHeap(), 0, family_nameW);
6195 LeaveCriticalSection( &freetype_cs );
6199 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6201 HFONTLIST *hfontlist;
6202 child->font = alloc_font();
6203 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6204 if(!child->font->ft_face)
6206 free_font(child->font);
6211 child->font->font_desc = font->font_desc;
6212 child->font->ntmFlags = child->face->ntmFlags;
6213 child->font->orientation = font->orientation;
6214 child->font->scale_y = font->scale_y;
6215 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6216 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6217 child->font->name = strdupW(child->face->family->FamilyName);
6218 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6219 child->font->base_font = font;
6220 list_add_head(&child_font_list, &child->font->entry);
6221 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6225 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6228 CHILD_FONT *child_font;
6231 font = font->base_font;
6233 *linked_font = font;
6235 if((*glyph = get_glyph_index(font, c)))
6238 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6240 if(!child_font->font)
6241 if(!load_child_font(font, child_font))
6244 if(!child_font->font->ft_face)
6246 g = get_glyph_index(child_font->font, c);
6250 *linked_font = child_font->font;
6257 /*************************************************************
6258 * WineEngGetCharWidth
6261 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6264 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6267 FT_UInt glyph_index;
6268 GdiFont *linked_font;
6270 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6273 EnterCriticalSection( &freetype_cs );
6274 for(c = firstChar; c <= lastChar; c++) {
6275 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6276 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6277 &gm, 0, NULL, &identity);
6278 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6280 LeaveCriticalSection( &freetype_cs );
6284 /*************************************************************
6285 * WineEngGetCharABCWidths
6288 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6291 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6294 FT_UInt glyph_index;
6295 GdiFont *linked_font;
6297 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6299 if(!FT_IS_SCALABLE(font->ft_face))
6303 EnterCriticalSection( &freetype_cs );
6305 for(c = firstChar; c <= lastChar; c++) {
6306 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6307 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6308 &gm, 0, NULL, &identity);
6309 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6310 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6311 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6312 FONT_GM(linked_font,glyph_index)->bbx;
6314 LeaveCriticalSection( &freetype_cs );
6318 /*************************************************************
6319 * WineEngGetCharABCWidthsFloat
6322 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6324 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6327 FT_UInt glyph_index;
6328 GdiFont *linked_font;
6330 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6333 EnterCriticalSection( &freetype_cs );
6335 for (c = first; c <= last; c++)
6337 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6338 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6339 &gm, 0, NULL, &identity);
6340 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6341 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6342 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6343 FONT_GM(linked_font, glyph_index)->lsb -
6344 FONT_GM(linked_font, glyph_index)->bbx;
6346 LeaveCriticalSection( &freetype_cs );
6350 /*************************************************************
6351 * WineEngGetCharABCWidthsI
6354 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6357 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6360 FT_UInt glyph_index;
6361 GdiFont *linked_font;
6363 if(!FT_HAS_HORIZONTAL(font->ft_face))
6367 EnterCriticalSection( &freetype_cs );
6369 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6371 for(c = firstChar; c < firstChar+count; c++) {
6372 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6373 &gm, 0, NULL, &identity);
6374 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6375 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6376 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6377 - FONT_GM(linked_font,c)->bbx;
6380 for(c = 0; c < count; c++) {
6381 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6382 &gm, 0, NULL, &identity);
6383 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6384 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6385 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6386 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6389 LeaveCriticalSection( &freetype_cs );
6393 /*************************************************************
6394 * WineEngGetTextExtentExPoint
6397 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6398 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6400 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6405 FT_UInt glyph_index;
6406 GdiFont *linked_font;
6408 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6412 EnterCriticalSection( &freetype_cs );
6415 WineEngGetTextMetrics(font, &tm);
6416 size->cy = tm.tmHeight;
6418 for(idx = 0; idx < count; idx++) {
6419 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6420 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6421 &gm, 0, NULL, &identity);
6422 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6424 if (! pnfit || ext <= max_ext) {
6434 LeaveCriticalSection( &freetype_cs );
6435 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6439 /*************************************************************
6440 * WineEngGetTextExtentExPointI
6443 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6444 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6446 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6452 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6455 EnterCriticalSection( &freetype_cs );
6458 WineEngGetTextMetrics(font, &tm);
6459 size->cy = tm.tmHeight;
6461 for(idx = 0; idx < count; idx++) {
6462 WineEngGetGlyphOutline(font, indices[idx],
6463 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6465 size->cx += FONT_GM(font,indices[idx])->adv;
6467 if (! pnfit || ext <= max_ext) {
6477 LeaveCriticalSection( &freetype_cs );
6478 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6482 /*************************************************************
6483 * WineEngGetFontData
6486 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6489 FT_Face ft_face = font->ft_face;
6493 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6494 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6495 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6497 if(!FT_IS_SFNT(ft_face))
6505 if(table) { /* MS tags differ in endianness from FT ones */
6506 table = table >> 24 | table << 24 |
6507 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6510 /* make sure value of len is the value freetype says it needs */
6513 FT_ULong needed = 0;
6514 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
6515 if( !err && needed < len) len = needed;
6517 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
6520 TRACE("Can't find table %c%c%c%c\n",
6521 /* bytes were reversed */
6522 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6523 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6529 /*************************************************************
6530 * WineEngGetTextFace
6533 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6535 INT n = strlenW(font->name) + 1;
6537 lstrcpynW(str, font->name, count);
6538 return min(count, n);
6543 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6545 if (fs) *fs = font->fs;
6546 return font->charset;
6549 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6551 GdiFont *font = dc->gdiFont, *linked_font;
6552 struct list *first_hfont;
6556 EnterCriticalSection( &freetype_cs );
6557 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6558 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6559 if(font == linked_font)
6560 *new_hfont = dc->hFont;
6563 first_hfont = list_head(&linked_font->hfontlist);
6564 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6566 LeaveCriticalSection( &freetype_cs );
6570 /* Retrieve a list of supported Unicode ranges for a given font.
6571 * Can be called with NULL gs to calculate the buffer size. Returns
6572 * the number of ranges found.
6574 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6576 DWORD num_ranges = 0;
6578 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6581 FT_ULong char_code, char_code_prev;
6584 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6586 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6587 face->num_glyphs, glyph_code, char_code);
6589 if (!glyph_code) return 0;
6593 gs->ranges[0].wcLow = (USHORT)char_code;
6594 gs->ranges[0].cGlyphs = 0;
6595 gs->cGlyphsSupported = 0;
6601 if (char_code < char_code_prev)
6603 ERR("expected increasing char code from FT_Get_Next_Char\n");
6606 if (char_code - char_code_prev > 1)
6611 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6612 gs->ranges[num_ranges - 1].cGlyphs = 1;
6613 gs->cGlyphsSupported++;
6618 gs->ranges[num_ranges - 1].cGlyphs++;
6619 gs->cGlyphsSupported++;
6621 char_code_prev = char_code;
6622 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6626 FIXME("encoding %u not supported\n", face->charmap->encoding);
6631 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6634 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6636 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6639 glyphset->cbThis = size;
6640 glyphset->cRanges = num_ranges;
6641 glyphset->flAccel = 0;
6646 /*************************************************************
6649 BOOL WineEngFontIsLinked(GdiFont *font)
6653 EnterCriticalSection( &freetype_cs );
6654 ret = !list_empty(&font->child_fonts);
6655 LeaveCriticalSection( &freetype_cs );
6659 static BOOL is_hinting_enabled(void)
6661 /* Use the >= 2.2.0 function if available */
6662 if(pFT_Get_TrueType_Engine_Type)
6664 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6665 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6667 #ifdef FT_DRIVER_HAS_HINTER
6672 /* otherwise if we've been compiled with < 2.2.0 headers
6673 use the internal macro */
6674 mod = pFT_Get_Module(library, "truetype");
6675 if(mod && FT_DRIVER_HAS_HINTER(mod))
6683 static BOOL is_subpixel_rendering_enabled( void )
6685 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6686 return pFT_Library_SetLcdFilter &&
6687 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6693 /*************************************************************************
6694 * GetRasterizerCaps (GDI32.@)
6696 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6698 static int hinting = -1;
6699 static int subpixel = -1;
6703 hinting = is_hinting_enabled();
6704 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6707 if ( subpixel == -1 )
6709 subpixel = is_subpixel_rendering_enabled();
6710 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6713 lprs->nSize = sizeof(RASTERIZER_STATUS);
6714 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6716 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6717 lprs->nLanguageID = 0;
6721 /*************************************************************
6722 * WineEngRealizationInfo
6724 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6726 FIXME("(%p, %p): stub!\n", font, info);
6729 if(FT_IS_SCALABLE(font->ft_face))
6732 info->cache_num = font->cache_num;
6733 info->unknown2 = -1;
6737 /*************************************************************************
6738 * Kerning support for TrueType fonts
6740 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6742 struct TT_kern_table
6748 struct TT_kern_subtable
6757 USHORT horizontal : 1;
6759 USHORT cross_stream: 1;
6760 USHORT override : 1;
6761 USHORT reserved1 : 4;
6767 struct TT_format0_kern_subtable
6771 USHORT entrySelector;
6782 static DWORD parse_format0_kern_subtable(GdiFont *font,
6783 const struct TT_format0_kern_subtable *tt_f0_ks,
6784 const USHORT *glyph_to_char,
6785 KERNINGPAIR *kern_pair, DWORD cPairs)
6788 const struct TT_kern_pair *tt_kern_pair;
6790 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6792 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6794 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6795 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6796 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6798 if (!kern_pair || !cPairs)
6801 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6803 nPairs = min(nPairs, cPairs);
6805 for (i = 0; i < nPairs; i++)
6807 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6808 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6809 /* this algorithm appears to better match what Windows does */
6810 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6811 if (kern_pair->iKernAmount < 0)
6813 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6814 kern_pair->iKernAmount -= font->ppem;
6816 else if (kern_pair->iKernAmount > 0)
6818 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6819 kern_pair->iKernAmount += font->ppem;
6821 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6823 TRACE("left %u right %u value %d\n",
6824 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6828 TRACE("copied %u entries\n", nPairs);
6832 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6836 const struct TT_kern_table *tt_kern_table;
6837 const struct TT_kern_subtable *tt_kern_subtable;
6839 USHORT *glyph_to_char;
6842 EnterCriticalSection( &freetype_cs );
6843 if (font->total_kern_pairs != (DWORD)-1)
6845 if (cPairs && kern_pair)
6847 cPairs = min(cPairs, font->total_kern_pairs);
6848 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6849 LeaveCriticalSection( &freetype_cs );
6852 LeaveCriticalSection( &freetype_cs );
6853 return font->total_kern_pairs;
6856 font->total_kern_pairs = 0;
6858 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6860 if (length == GDI_ERROR)
6862 TRACE("no kerning data in the font\n");
6863 LeaveCriticalSection( &freetype_cs );
6867 buf = HeapAlloc(GetProcessHeap(), 0, length);
6870 WARN("Out of memory\n");
6871 LeaveCriticalSection( &freetype_cs );
6875 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6877 /* build a glyph index to char code map */
6878 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6881 WARN("Out of memory allocating a glyph index to char code map\n");
6882 HeapFree(GetProcessHeap(), 0, buf);
6883 LeaveCriticalSection( &freetype_cs );
6887 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
6893 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6895 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6896 font->ft_face->num_glyphs, glyph_code, char_code);
6900 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6902 /* FIXME: This doesn't match what Windows does: it does some fancy
6903 * things with duplicate glyph index to char code mappings, while
6904 * we just avoid overriding existing entries.
6906 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6907 glyph_to_char[glyph_code] = (USHORT)char_code;
6909 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6916 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6917 for (n = 0; n <= 65535; n++)
6918 glyph_to_char[n] = (USHORT)n;
6921 tt_kern_table = buf;
6922 nTables = GET_BE_WORD(tt_kern_table->nTables);
6923 TRACE("version %u, nTables %u\n",
6924 GET_BE_WORD(tt_kern_table->version), nTables);
6926 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6928 for (i = 0; i < nTables; i++)
6930 struct TT_kern_subtable tt_kern_subtable_copy;
6932 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6933 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6934 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6936 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6937 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6938 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6940 /* According to the TrueType specification this is the only format
6941 * that will be properly interpreted by Windows and OS/2
6943 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6945 DWORD new_chunk, old_total = font->total_kern_pairs;
6947 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6948 glyph_to_char, NULL, 0);
6949 font->total_kern_pairs += new_chunk;
6951 if (!font->kern_pairs)
6952 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6953 font->total_kern_pairs * sizeof(*font->kern_pairs));
6955 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6956 font->total_kern_pairs * sizeof(*font->kern_pairs));
6958 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6959 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6962 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6964 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6967 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6968 HeapFree(GetProcessHeap(), 0, buf);
6970 if (cPairs && kern_pair)
6972 cPairs = min(cPairs, font->total_kern_pairs);
6973 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6974 LeaveCriticalSection( &freetype_cs );
6977 LeaveCriticalSection( &freetype_cs );
6978 return font->total_kern_pairs;
6981 #else /* HAVE_FREETYPE */
6983 /*************************************************************************/
6985 BOOL WineEngInit(void)
6989 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6993 BOOL WineEngDestroyFontInstance(HFONT hfont)
6998 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
7003 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
7004 LPWORD pgi, DWORD flags)
7009 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
7010 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
7013 ERR("called but we don't have FreeType\n");
7017 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
7019 ERR("called but we don't have FreeType\n");
7023 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
7024 OUTLINETEXTMETRICW *potm)
7026 ERR("called but we don't have FreeType\n");
7030 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
7033 ERR("called but we don't have FreeType\n");
7037 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
7040 ERR("called but we don't have FreeType\n");
7044 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
7046 ERR("called but we don't have FreeType\n");
7050 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
7053 ERR("called but we don't have FreeType\n");
7057 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
7058 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
7060 ERR("called but we don't have FreeType\n");
7064 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
7065 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
7067 ERR("called but we don't have FreeType\n");
7071 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
7074 ERR("called but we don't have FreeType\n");
7078 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
7080 ERR("called but we don't have FreeType\n");
7084 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7086 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7090 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7092 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7096 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7098 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7102 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
7104 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
7105 return DEFAULT_CHARSET;
7108 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7113 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
7115 FIXME("(%p, %p): stub\n", font, glyphset);
7119 BOOL WineEngFontIsLinked(GdiFont *font)
7124 /*************************************************************************
7125 * GetRasterizerCaps (GDI32.@)
7127 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7129 lprs->nSize = sizeof(RASTERIZER_STATUS);
7131 lprs->nLanguageID = 0;
7135 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
7137 ERR("called but we don't have FreeType\n");
7141 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
7143 ERR("called but we don't have FreeType\n");
7147 #endif /* HAVE_FREETYPE */