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 struct freetype_physdev
380 struct gdi_physdev dev;
384 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
386 return (struct freetype_physdev *)dev;
389 static const struct gdi_dc_funcs freetype_funcs;
391 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
392 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
393 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
395 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
396 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
397 'W','i','n','d','o','w','s','\\',
398 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
399 'F','o','n','t','s','\0'};
401 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
402 'W','i','n','d','o','w','s',' ','N','T','\\',
403 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
404 'F','o','n','t','s','\0'};
406 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
407 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
408 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
409 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
411 static const WCHAR * const SystemFontValues[4] = {
418 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
419 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
421 /* Interesting and well-known (frequently-assumed!) font names */
422 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
423 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 };
424 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
425 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
426 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
427 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
428 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
429 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
431 static const WCHAR arial[] = {'A','r','i','a','l',0};
432 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
433 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};
434 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};
435 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
436 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
437 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
438 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
439 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
441 static const WCHAR *default_serif_list[] =
445 bitstream_vera_serif,
449 static const WCHAR *default_fixed_list[] =
453 bitstream_vera_sans_mono,
457 static const WCHAR *default_sans_list[] =
466 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
467 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
468 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
469 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
470 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
471 'E','u','r','o','p','e','a','n','\0'};
472 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
473 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
474 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
475 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
476 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
477 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
478 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
479 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
480 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
481 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
482 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
483 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
485 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
495 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
503 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
512 typedef struct tagFontSubst {
518 /* Registry font cache key and value names */
519 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
520 'F','o','n','t','s',0};
521 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
522 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
523 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
524 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
525 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
526 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
527 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
528 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
529 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
530 static const WCHAR face_size_value[] = {'S','i','z','e',0};
531 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
532 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
533 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
534 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
535 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
548 static struct list mappings_list = LIST_INIT( mappings_list );
550 static CRITICAL_SECTION freetype_cs;
551 static CRITICAL_SECTION_DEBUG critsect_debug =
554 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
555 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
557 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
559 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
561 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
562 static BOOL use_default_fallback = FALSE;
564 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
565 static BOOL get_outline_text_metrics(GdiFont *font);
566 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
568 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
569 'W','i','n','d','o','w','s',' ','N','T','\\',
570 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
571 'S','y','s','t','e','m','L','i','n','k',0};
573 /****************************************
574 * Notes on .fon files
576 * The fonts System, FixedSys and Terminal are special. There are typically multiple
577 * versions installed for different resolutions and codepages. Windows stores which one to use
578 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
580 * FIXEDFON.FON FixedSys
582 * OEMFONT.FON Terminal
583 * LogPixels Current dpi set by the display control panel applet
584 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
585 * also has a LogPixels value that appears to mirror this)
587 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
588 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
589 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
590 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
591 * so that makes sense.
593 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
594 * to be mapped into the registry on Windows 2000 at least).
597 * ega80woa.fon=ega80850.fon
598 * ega40woa.fon=ega40850.fon
599 * cga80woa.fon=cga80850.fon
600 * cga40woa.fon=cga40850.fon
603 /* These are all structures needed for the GSUB table */
605 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
606 #define TATEGAKI_LOWER_BOUND 0x02F1
622 GSUB_ScriptRecord ScriptRecord[1];
628 } GSUB_LangSysRecord;
633 GSUB_LangSysRecord LangSysRecord[1];
637 WORD LookupOrder; /* Reserved */
638 WORD ReqFeatureIndex;
640 WORD FeatureIndex[1];
646 } GSUB_FeatureRecord;
650 GSUB_FeatureRecord FeatureRecord[1];
654 WORD FeatureParams; /* Reserved */
656 WORD LookupListIndex[1];
675 } GSUB_CoverageFormat1;
680 WORD StartCoverageIndex;
686 GSUB_RangeRecord RangeRecord[1];
687 } GSUB_CoverageFormat2;
690 WORD SubstFormat; /* = 1 */
693 } GSUB_SingleSubstFormat1;
696 WORD SubstFormat; /* = 2 */
700 }GSUB_SingleSubstFormat2;
702 #ifdef HAVE_CARBON_CARBON_H
703 static char *find_cache_dir(void)
707 static char cached_path[MAX_PATH];
708 static const char *wine = "/Wine", *fonts = "/Fonts";
710 if(*cached_path) return cached_path;
712 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
715 WARN("can't create cached data folder\n");
718 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
721 WARN("can't create cached data path\n");
725 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
727 ERR("Could not create full path\n");
731 strcat(cached_path, wine);
733 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
735 WARN("Couldn't mkdir %s\n", cached_path);
739 strcat(cached_path, fonts);
740 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
742 WARN("Couldn't mkdir %s\n", cached_path);
749 /******************************************************************
752 * Extracts individual TrueType font files from a Mac suitcase font
753 * and saves them into the user's caches directory (see
755 * Returns a NULL terminated array of filenames.
757 * We do this because they are apps that try to read ttf files
758 * themselves and they don't like Mac suitcase files.
760 static char **expand_mac_font(const char *path)
767 const char *filename;
771 unsigned int size, max_size;
774 TRACE("path %s\n", path);
776 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
779 WARN("failed to get ref\n");
783 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
786 TRACE("no data fork, so trying resource fork\n");
787 res_ref = FSOpenResFile(&ref, fsRdPerm);
790 TRACE("unable to open resource fork\n");
797 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
800 CloseResFile(res_ref);
804 out_dir = find_cache_dir();
806 filename = strrchr(path, '/');
807 if(!filename) filename = path;
810 /* output filename has the form out_dir/filename_%04x.ttf */
811 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
818 unsigned short *num_faces_ptr, num_faces, face;
821 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
823 fond = Get1IndResource(fond_res, idx);
825 TRACE("got fond resource %d\n", idx);
828 fam_rec = *(FamRec**)fond;
829 num_faces_ptr = (unsigned short *)(fam_rec + 1);
830 num_faces = GET_BE_WORD(*num_faces_ptr);
832 assoc = (AsscEntry*)(num_faces_ptr + 1);
833 TRACE("num faces %04x\n", num_faces);
834 for(face = 0; face < num_faces; face++, assoc++)
837 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
838 unsigned short size, font_id;
841 size = GET_BE_WORD(assoc->fontSize);
842 font_id = GET_BE_WORD(assoc->fontID);
845 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
849 TRACE("trying to load sfnt id %04x\n", font_id);
850 sfnt = GetResource(sfnt_res, font_id);
853 TRACE("can't get sfnt resource %04x\n", font_id);
857 output = HeapAlloc(GetProcessHeap(), 0, output_len);
862 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
864 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
865 if(fd != -1 || errno == EEXIST)
869 unsigned char *sfnt_data;
872 sfnt_data = *(unsigned char**)sfnt;
873 write(fd, sfnt_data, GetHandleSize(sfnt));
877 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
880 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
882 ret.array[ret.size++] = output;
886 WARN("unable to create %s\n", output);
887 HeapFree(GetProcessHeap(), 0, output);
890 ReleaseResource(sfnt);
893 ReleaseResource(fond);
896 CloseResFile(res_ref);
901 #endif /* HAVE_CARBON_CARBON_H */
903 static inline BOOL is_win9x(void)
905 return GetVersion() & 0x80000000;
908 This function builds an FT_Fixed from a double. It fails if the absolute
909 value of the float number is greater than 32768.
911 static inline FT_Fixed FT_FixedFromFloat(double f)
917 This function builds an FT_Fixed from a FIXED. It simply put f.value
918 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
920 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
922 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
926 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
931 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
932 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
934 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
935 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
937 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
939 if(face_name && strcmpiW(face_name, family->FamilyName))
941 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
945 file = strrchr(face->file, '/');
950 if(!strcasecmp(file, file_nameA))
952 HeapFree(GetProcessHeap(), 0, file_nameA);
957 HeapFree(GetProcessHeap(), 0, file_nameA);
961 static Family *find_family_from_name(const WCHAR *name)
965 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
967 if(!strcmpiW(family->FamilyName, name))
974 static void DumpSubstList(void)
978 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
980 if(psub->from.charset != -1 || psub->to.charset != -1)
981 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
982 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
984 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
985 debugstr_w(psub->to.name));
990 static LPWSTR strdupW(LPCWSTR p)
993 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
994 ret = HeapAlloc(GetProcessHeap(), 0, len);
999 static LPSTR strdupA(LPCSTR p)
1002 DWORD len = (strlen(p) + 1);
1003 ret = HeapAlloc(GetProcessHeap(), 0, len);
1004 memcpy(ret, p, len);
1008 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1013 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1015 if(!strcmpiW(element->from.name, from_name) &&
1016 (element->from.charset == from_charset ||
1017 element->from.charset == -1))
1024 #define ADD_FONT_SUBST_FORCE 1
1026 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1028 FontSubst *from_exist, *to_exist;
1030 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1032 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1034 list_remove(&from_exist->entry);
1035 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1036 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1037 HeapFree(GetProcessHeap(), 0, from_exist);
1043 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1047 HeapFree(GetProcessHeap(), 0, subst->to.name);
1048 subst->to.name = strdupW(to_exist->to.name);
1051 list_add_tail(subst_list, &subst->entry);
1056 HeapFree(GetProcessHeap(), 0, subst->from.name);
1057 HeapFree(GetProcessHeap(), 0, subst->to.name);
1058 HeapFree(GetProcessHeap(), 0, subst);
1062 static void split_subst_info(NameCs *nc, LPSTR str)
1064 CHAR *p = strrchr(str, ',');
1069 nc->charset = strtol(p+1, NULL, 10);
1072 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1073 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1074 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1077 static void LoadSubstList(void)
1081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey) == ERROR_SUCCESS) {
1089 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1090 &valuelen, &datalen, NULL, NULL);
1092 valuelen++; /* returned value doesn't include room for '\0' */
1093 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1094 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1098 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1099 &dlen) == ERROR_SUCCESS) {
1100 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1102 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1103 split_subst_info(&psub->from, value);
1104 split_subst_info(&psub->to, data);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1109 psub->to.charset == DEFAULT_CHARSET) {
1110 HeapFree(GetProcessHeap(), 0, psub->to.name);
1111 HeapFree(GetProcessHeap(), 0, psub->from.name);
1112 HeapFree(GetProcessHeap(), 0, psub);
1114 add_font_subst(&font_subst_list, psub, 0);
1116 /* reset dlen and vlen */
1120 HeapFree(GetProcessHeap(), 0, data);
1121 HeapFree(GetProcessHeap(), 0, value);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1138 FT_UInt num_names, name_index;
1140 if(FT_IS_SFNT(ft_face))
1142 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1144 for(name_index = 0; name_index < num_names; name_index++)
1146 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1148 if((name.platform_id == req->platform_id) &&
1149 (name.encoding_id == req->encoding_id) &&
1150 (name.language_id == req->language_id) &&
1151 (name.name_id == req->name_id))
1153 req->string = name.string;
1154 req->string_len = name.string_len;
1161 req->string_len = 0;
1165 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1170 name.platform_id = TT_PLATFORM_MICROSOFT;
1171 name.encoding_id = TT_MS_ID_UNICODE_CS;
1172 name.language_id = language_id;
1173 name.name_id = name_id;
1175 if(get_name_table_entry(ft_face, &name))
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1181 for(i = 0; i < name.string_len / 2; i++)
1183 WORD *tmp = (WORD *)&name.string[i * 2];
1184 ret[i] = GET_BE_WORD(*tmp);
1187 TRACE("Got localised name %s\n", debugstr_w(ret));
1193 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1196 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1197 if(r != ERROR_SUCCESS) return r;
1198 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1199 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1202 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1204 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1207 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1210 DWORD num_strikes, max_strike_key_len;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1218 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1219 face->cached_enum_data = NULL;
1221 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1222 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1224 face->StyleName = strdupW(face_name);
1225 face->family = family;
1227 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1229 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1230 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1231 face->FullName = fullName;
1234 face->FullName = NULL;
1236 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1237 reg_load_dword(hkey_face, face_italic_value, &italic);
1238 reg_load_dword(hkey_face, face_bold_value, &bold);
1239 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1240 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1242 needed = sizeof(face->fs);
1243 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1244 memset(&face->fs_links, 0, sizeof(face->fs_links));
1246 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1248 face->scalable = TRUE;
1249 memset(&face->size, 0, sizeof(face->size));
1253 face->scalable = FALSE;
1254 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1255 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1256 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1257 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1258 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face->size.height, face->size.width, face->size.size >> 6,
1262 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1266 if (italic) face->ntmFlags |= NTM_ITALIC;
1267 if (bold) face->ntmFlags |= NTM_BOLD;
1268 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face->fs.fsCsb[0], face->fs.fsCsb[1],
1272 face->fs.fsUsb[0], face->fs.fsUsb[1],
1273 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1275 if(!italic && !bold)
1276 list_add_head(&family->faces, &face->entry);
1278 list_add_tail(&family->faces, &face->entry);
1280 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1285 NULL, NULL, NULL, NULL);
1286 if(num_strikes != 0)
1288 WCHAR strike_name[10];
1289 DWORD strike_index = 0;
1291 needed = sizeof(strike_name) / sizeof(WCHAR);
1292 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1293 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1296 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1297 load_face(hkey_strike, face_name, family);
1298 RegCloseKey(hkey_strike);
1299 needed = sizeof(strike_name) / sizeof(WCHAR);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache)
1306 DWORD max_family_key_len, size;
1308 DWORD family_index = 0;
1312 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1313 NULL, NULL, NULL, NULL);
1314 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1316 size = max_family_key_len + 1;
1317 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1318 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1320 WCHAR *english_family = NULL;
1321 DWORD face_index = 0;
1323 DWORD max_face_key_len;
1325 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1326 TRACE("opened family key %s\n", debugstr_w(family_name));
1327 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1329 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1330 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1333 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1334 family->FamilyName = strdupW(family_name);
1335 family->EnglishName = english_family;
1336 list_init(&family->faces);
1337 list_add_tail(&font_list, &family->entry);
1341 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1342 subst->from.name = strdupW(english_family);
1343 subst->from.charset = -1;
1344 subst->to.name = strdupW(family_name);
1345 subst->to.charset = -1;
1346 add_font_subst(&font_subst_list, subst, 0);
1349 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1350 NULL, NULL, NULL, NULL);
1352 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1353 size = max_face_key_len + 1;
1354 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1355 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1359 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1360 load_face(hkey_face, face_name, family);
1361 RegCloseKey(hkey_face);
1362 size = max_face_key_len + 1;
1364 HeapFree(GetProcessHeap(), 0, face_name);
1365 RegCloseKey(hkey_family);
1366 size = max_family_key_len + 1;
1369 HeapFree(GetProcessHeap(), 0, family_name);
1372 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1375 HKEY hkey_wine_fonts;
1377 /* We don't want to create the fonts key as volatile, so open this first */
1378 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1379 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1380 if(ret != ERROR_SUCCESS)
1382 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1386 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1387 KEY_ALL_ACCESS, NULL, hkey, disposition);
1388 RegCloseKey(hkey_wine_fonts);
1392 static void add_face_to_cache(Face *face)
1394 HKEY hkey_font_cache, hkey_family, hkey_face;
1395 WCHAR *face_key_name;
1397 create_font_cache_key(&hkey_font_cache, NULL);
1399 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1400 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1401 if(face->family->EnglishName)
1402 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1403 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1406 face_key_name = face->StyleName;
1409 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1410 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1411 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1413 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1416 HeapFree(GetProcessHeap(), 0, face_key_name);
1418 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1420 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1421 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1423 reg_save_dword(hkey_face, face_index_value, face->face_index);
1424 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1425 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1426 reg_save_dword(hkey_face, face_version_value, face->font_version);
1427 reg_save_dword(hkey_face, face_external_value, face->external);
1429 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1433 reg_save_dword(hkey_face, face_height_value, face->size.height);
1434 reg_save_dword(hkey_face, face_width_value, face->size.width);
1435 reg_save_dword(hkey_face, face_size_value, face->size.size);
1436 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1437 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1438 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1440 RegCloseKey(hkey_face);
1441 RegCloseKey(hkey_family);
1442 RegCloseKey(hkey_font_cache);
1445 static inline int TestStyles(DWORD flags, DWORD styles)
1447 return (flags & styles) == styles;
1450 static int StyleOrdering(Face *face)
1452 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1454 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1456 if (TestStyles(face->ntmFlags, NTM_BOLD))
1458 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1461 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1462 debugstr_w(face->family->FamilyName),
1463 debugstr_w(face->StyleName),
1469 /* Add a style of face to a font family using an ordering of the list such
1470 that regular fonts come before bold and italic, and single styles come
1471 before compound styles. */
1472 static void AddFaceToFamily(Face *face, Family *family)
1476 LIST_FOR_EACH( entry, &family->faces )
1478 Face *ent = LIST_ENTRY(entry, Face, entry);
1479 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1481 list_add_before( entry, &face->entry );
1484 #define ADDFONT_EXTERNAL_FONT 0x01
1485 #define ADDFONT_FORCE_BITMAP 0x02
1486 #define ADDFONT_ADD_TO_CACHE 0x04
1488 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1492 TT_Header *pHeader = NULL;
1493 WCHAR *english_family, *localised_family, *StyleW;
1497 struct list *family_elem_ptr, *face_elem_ptr;
1499 FT_Long face_index = 0, num_faces;
1500 FT_WinFNT_HeaderRec winfnt_header;
1501 int i, bitmap_num, internal_leading;
1504 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1505 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1507 #ifdef HAVE_CARBON_CARBON_H
1508 if(file && !fake_family)
1510 char **mac_list = expand_mac_font(file);
1513 BOOL had_one = FALSE;
1515 for(cursor = mac_list; *cursor; cursor++)
1518 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1519 HeapFree(GetProcessHeap(), 0, *cursor);
1521 HeapFree(GetProcessHeap(), 0, mac_list);
1526 #endif /* HAVE_CARBON_CARBON_H */
1529 char *family_name = fake_family;
1533 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1534 err = pFT_New_Face(library, file, face_index, &ft_face);
1537 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1538 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1542 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1546 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*/
1547 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1548 pFT_Done_Face(ft_face);
1552 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1553 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1554 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1555 pFT_Done_Face(ft_face);
1559 if(FT_IS_SFNT(ft_face))
1561 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1562 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1563 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1565 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1566 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1567 pFT_Done_Face(ft_face);
1571 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1572 we don't want to load these. */
1573 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1577 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1579 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1580 pFT_Done_Face(ft_face);
1586 if(!ft_face->family_name || !ft_face->style_name) {
1587 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1588 pFT_Done_Face(ft_face);
1592 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1594 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1595 pFT_Done_Face(ft_face);
1601 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1602 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1604 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1605 HeapFree(GetProcessHeap(), 0, localised_family);
1606 num_faces = ft_face->num_faces;
1607 pFT_Done_Face(ft_face);
1610 HeapFree(GetProcessHeap(), 0, localised_family);
1614 family_name = ft_face->family_name;
1618 My_FT_Bitmap_Size *size = NULL;
1621 if(!FT_IS_SCALABLE(ft_face))
1622 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1624 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1625 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1626 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1628 localised_family = NULL;
1630 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1631 if(localised_family && !strcmpiW(localised_family, english_family)) {
1632 HeapFree(GetProcessHeap(), 0, localised_family);
1633 localised_family = NULL;
1638 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1639 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1640 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1645 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1646 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1647 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1648 list_init(&family->faces);
1649 list_add_tail(&font_list, &family->entry);
1651 if(localised_family) {
1652 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1653 subst->from.name = strdupW(english_family);
1654 subst->from.charset = -1;
1655 subst->to.name = strdupW(localised_family);
1656 subst->to.charset = -1;
1657 add_font_subst(&font_subst_list, subst, 0);
1660 HeapFree(GetProcessHeap(), 0, localised_family);
1661 HeapFree(GetProcessHeap(), 0, english_family);
1663 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1664 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1665 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1667 internal_leading = 0;
1668 memset(&fs, 0, sizeof(fs));
1670 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1672 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1673 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1674 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1675 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1676 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1677 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1678 if(pOS2->version == 0) {
1681 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1682 fs.fsCsb[0] |= FS_LATIN1;
1684 fs.fsCsb[0] |= FS_SYMBOL;
1687 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1689 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1690 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1691 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1693 internal_leading = winfnt_header.internal_leading;
1696 face_elem_ptr = list_head(&family->faces);
1697 while(face_elem_ptr) {
1698 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1699 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1700 if(!strcmpiW(face->StyleName, StyleW) &&
1701 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1702 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1703 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1704 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1707 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1708 HeapFree(GetProcessHeap(), 0, StyleW);
1709 pFT_Done_Face(ft_face);
1712 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1713 TRACE("Original font is newer so skipping this one\n");
1714 HeapFree(GetProcessHeap(), 0, StyleW);
1715 pFT_Done_Face(ft_face);
1718 TRACE("Replacing original with this one\n");
1719 list_remove(&face->entry);
1720 HeapFree(GetProcessHeap(), 0, face->file);
1721 HeapFree(GetProcessHeap(), 0, face->StyleName);
1722 HeapFree(GetProcessHeap(), 0, face->FullName);
1723 HeapFree(GetProcessHeap(), 0, face);
1728 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1729 face->cached_enum_data = NULL;
1730 face->StyleName = StyleW;
1731 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1734 face->file = strdupA(file);
1735 face->font_data_ptr = NULL;
1736 face->font_data_size = 0;
1741 face->font_data_ptr = font_data_ptr;
1742 face->font_data_size = font_data_size;
1744 face->face_index = face_index;
1746 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1747 face->ntmFlags |= NTM_ITALIC;
1748 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1749 face->ntmFlags |= NTM_BOLD;
1750 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1751 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1752 face->family = family;
1753 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1755 memset(&face->fs_links, 0, sizeof(face->fs_links));
1757 if(FT_IS_SCALABLE(ft_face)) {
1758 memset(&face->size, 0, sizeof(face->size));
1759 face->scalable = TRUE;
1761 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1762 size->height, size->width, size->size >> 6,
1763 size->x_ppem >> 6, size->y_ppem >> 6);
1764 face->size.height = size->height;
1765 face->size.width = size->width;
1766 face->size.size = size->size;
1767 face->size.x_ppem = size->x_ppem;
1768 face->size.y_ppem = size->y_ppem;
1769 face->size.internal_leading = internal_leading;
1770 face->scalable = FALSE;
1773 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1775 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1777 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1778 face->ntmFlags |= NTM_PS_OPENTYPE;
1781 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1782 face->fs.fsCsb[0], face->fs.fsCsb[1],
1783 face->fs.fsUsb[0], face->fs.fsUsb[1],
1784 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1787 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1788 for(i = 0; i < ft_face->num_charmaps; i++) {
1789 switch(ft_face->charmaps[i]->encoding) {
1790 case FT_ENCODING_UNICODE:
1791 case FT_ENCODING_APPLE_ROMAN:
1792 face->fs.fsCsb[0] |= FS_LATIN1;
1794 case FT_ENCODING_MS_SYMBOL:
1795 face->fs.fsCsb[0] |= FS_SYMBOL;
1803 if(flags & ADDFONT_ADD_TO_CACHE)
1804 add_face_to_cache(face);
1806 AddFaceToFamily(face, family);
1808 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1810 num_faces = ft_face->num_faces;
1811 pFT_Done_Face(ft_face);
1812 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1813 debugstr_w(StyleW));
1814 } while(num_faces > ++face_index);
1818 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1820 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1823 static void DumpFontList(void)
1827 struct list *family_elem_ptr, *face_elem_ptr;
1829 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1830 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1831 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1832 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1833 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1834 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1836 TRACE(" %d", face->size.height);
1843 /***********************************************************
1844 * The replacement list is a way to map an entire font
1845 * family onto another family. For example adding
1847 * [HKCU\Software\Wine\Fonts\Replacements]
1848 * "Wingdings"="Winedings"
1850 * would enumerate the Winedings font both as Winedings and
1851 * Wingdings. However if a real Wingdings font is present the
1852 * replacement does not take place.
1855 static void LoadReplaceList(void)
1858 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1863 struct list *family_elem_ptr, *face_elem_ptr;
1866 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1867 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1869 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1870 &valuelen, &datalen, NULL, NULL);
1872 valuelen++; /* returned value doesn't include room for '\0' */
1873 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1874 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1878 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1879 &dlen) == ERROR_SUCCESS) {
1880 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1881 /* "NewName"="Oldname" */
1882 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1884 if(!find_family_from_name(value))
1886 /* Find the old family and hence all of the font files
1888 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1889 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1890 if(!strcmpiW(family->FamilyName, data)) {
1891 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1892 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1893 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1894 debugstr_w(face->StyleName), familyA);
1895 /* Now add a new entry with the new family name */
1896 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1897 familyA, family->FamilyName,
1898 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1904 /* reset dlen and vlen */
1908 HeapFree(GetProcessHeap(), 0, data);
1909 HeapFree(GetProcessHeap(), 0, value);
1914 /*************************************************************
1917 static BOOL init_system_links(void)
1921 DWORD type, max_val, max_data, val_len, data_len, index;
1922 WCHAR *value, *data;
1923 WCHAR *entry, *next;
1924 SYSTEM_LINKS *font_link, *system_font_link;
1925 CHILD_FONT *child_font;
1926 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1927 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1933 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1935 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1936 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1937 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1938 val_len = max_val + 1;
1939 data_len = max_data;
1941 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1943 memset(&fs, 0, sizeof(fs));
1944 psub = get_font_subst(&font_subst_list, value, -1);
1945 /* Don't store fonts that are only substitutes for other fonts */
1948 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1951 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1952 font_link->font_name = strdupW(value);
1953 list_init(&font_link->links);
1954 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1957 CHILD_FONT *child_font;
1959 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1961 next = entry + strlenW(entry) + 1;
1963 face_name = strchrW(entry, ',');
1967 while(isspaceW(*face_name))
1970 psub = get_font_subst(&font_subst_list, face_name, -1);
1972 face_name = psub->to.name;
1974 face = find_face_from_filename(entry, face_name);
1977 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1981 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1982 child_font->face = face;
1983 child_font->font = NULL;
1984 fs.fsCsb[0] |= face->fs.fsCsb[0];
1985 fs.fsCsb[1] |= face->fs.fsCsb[1];
1986 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1987 list_add_tail(&font_link->links, &child_font->entry);
1989 family = find_family_from_name(font_link->font_name);
1992 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1994 face->fs_links = fs;
1997 list_add_tail(&system_links, &font_link->entry);
1999 val_len = max_val + 1;
2000 data_len = max_data;
2003 HeapFree(GetProcessHeap(), 0, value);
2004 HeapFree(GetProcessHeap(), 0, data);
2008 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2011 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2012 system_font_link->font_name = strdupW(System);
2013 list_init(&system_font_link->links);
2015 face = find_face_from_filename(tahoma_ttf, Tahoma);
2018 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2019 child_font->face = face;
2020 child_font->font = NULL;
2021 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2022 list_add_tail(&system_font_link->links, &child_font->entry);
2024 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2026 if(!strcmpiW(font_link->font_name, Tahoma))
2028 CHILD_FONT *font_link_entry;
2029 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2031 CHILD_FONT *new_child;
2032 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2033 new_child->face = font_link_entry->face;
2034 new_child->font = NULL;
2035 list_add_tail(&system_font_link->links, &new_child->entry);
2040 list_add_tail(&system_links, &system_font_link->entry);
2044 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2047 struct dirent *dent;
2048 char path[MAX_PATH];
2050 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2052 dir = opendir(dirname);
2054 WARN("Can't open directory %s\n", debugstr_a(dirname));
2057 while((dent = readdir(dir)) != NULL) {
2058 struct stat statbuf;
2060 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2063 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2065 sprintf(path, "%s/%s", dirname, dent->d_name);
2067 if(stat(path, &statbuf) == -1)
2069 WARN("Can't stat %s\n", debugstr_a(path));
2072 if(S_ISDIR(statbuf.st_mode))
2073 ReadFontDir(path, external_fonts);
2076 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2077 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2078 AddFontFileToList(path, NULL, NULL, addfont_flags);
2085 static void load_fontconfig_fonts(void)
2087 #ifdef SONAME_LIBFONTCONFIG
2088 void *fc_handle = NULL;
2097 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2099 TRACE("Wine cannot find the fontconfig library (%s).\n",
2100 SONAME_LIBFONTCONFIG);
2103 #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;}
2104 LOAD_FUNCPTR(FcConfigGetCurrent);
2105 LOAD_FUNCPTR(FcFontList);
2106 LOAD_FUNCPTR(FcFontSetDestroy);
2107 LOAD_FUNCPTR(FcInit);
2108 LOAD_FUNCPTR(FcObjectSetAdd);
2109 LOAD_FUNCPTR(FcObjectSetCreate);
2110 LOAD_FUNCPTR(FcObjectSetDestroy);
2111 LOAD_FUNCPTR(FcPatternCreate);
2112 LOAD_FUNCPTR(FcPatternDestroy);
2113 LOAD_FUNCPTR(FcPatternGetBool);
2114 LOAD_FUNCPTR(FcPatternGetString);
2117 if(!pFcInit()) return;
2119 config = pFcConfigGetCurrent();
2120 pat = pFcPatternCreate();
2121 os = pFcObjectSetCreate();
2122 pFcObjectSetAdd(os, FC_FILE);
2123 pFcObjectSetAdd(os, FC_SCALABLE);
2124 fontset = pFcFontList(config, pat, os);
2125 if(!fontset) return;
2126 for(i = 0; i < fontset->nfont; i++) {
2129 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2131 TRACE("fontconfig: %s\n", file);
2133 /* We're just interested in OT/TT fonts for now, so this hack just
2134 picks up the scalable fonts without extensions .pf[ab] to save time
2135 loading every other font */
2137 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2139 TRACE("not scalable\n");
2143 len = strlen( file );
2144 if(len < 4) continue;
2145 ext = &file[ len - 3 ];
2146 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2147 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2149 pFcFontSetDestroy(fontset);
2150 pFcObjectSetDestroy(os);
2151 pFcPatternDestroy(pat);
2157 static BOOL load_font_from_data_dir(LPCWSTR file)
2160 const char *data_dir = wine_get_data_dir();
2162 if (!data_dir) data_dir = wine_get_build_dir();
2169 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2171 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2173 strcpy(unix_name, data_dir);
2174 strcat(unix_name, "/fonts/");
2176 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2178 EnterCriticalSection( &freetype_cs );
2179 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2180 LeaveCriticalSection( &freetype_cs );
2181 HeapFree(GetProcessHeap(), 0, unix_name);
2186 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2188 static const WCHAR slashW[] = {'\\','\0'};
2190 WCHAR windowsdir[MAX_PATH];
2193 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2194 strcatW(windowsdir, fontsW);
2195 strcatW(windowsdir, slashW);
2196 strcatW(windowsdir, file);
2197 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2198 EnterCriticalSection( &freetype_cs );
2199 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2200 LeaveCriticalSection( &freetype_cs );
2201 HeapFree(GetProcessHeap(), 0, unixname);
2206 static void load_system_fonts(void)
2209 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2210 const WCHAR * const *value;
2212 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2215 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2216 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2217 strcatW(windowsdir, fontsW);
2218 for(value = SystemFontValues; *value; value++) {
2219 dlen = sizeof(data);
2220 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2224 sprintfW(pathW, fmtW, windowsdir, data);
2225 if((unixname = wine_get_unix_file_name(pathW))) {
2226 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2227 HeapFree(GetProcessHeap(), 0, unixname);
2230 load_font_from_data_dir(data);
2237 /*************************************************************
2239 * This adds registry entries for any externally loaded fonts
2240 * (fonts from fontconfig or FontDirs). It also deletes entries
2241 * of no longer existing fonts.
2244 static void update_reg_entries(void)
2246 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2251 struct list *family_elem_ptr, *face_elem_ptr;
2253 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2254 static const WCHAR spaceW[] = {' ', '\0'};
2257 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2258 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2259 ERR("Can't create Windows font reg key\n");
2263 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2264 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2265 ERR("Can't create Windows font reg key\n");
2269 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2270 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2271 ERR("Can't create external font reg key\n");
2275 /* enumerate the fonts and add external ones to the two keys */
2277 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2278 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2279 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2280 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2281 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2282 if(!face->external) continue;
2284 if (!(face->ntmFlags & NTM_REGULAR))
2285 len = len_fam + strlenW(face->StyleName) + 1;
2286 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2287 strcpyW(valueW, family->FamilyName);
2288 if(len != len_fam) {
2289 strcatW(valueW, spaceW);
2290 strcatW(valueW, face->StyleName);
2292 strcatW(valueW, TrueType);
2294 file = wine_get_dos_file_name(face->file);
2296 len = strlenW(file) + 1;
2299 if((path = strrchr(face->file, '/')) == NULL)
2303 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2305 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2306 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2308 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2309 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2310 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2312 HeapFree(GetProcessHeap(), 0, file);
2313 HeapFree(GetProcessHeap(), 0, valueW);
2317 if(external_key) RegCloseKey(external_key);
2318 if(win9x_key) RegCloseKey(win9x_key);
2319 if(winnt_key) RegCloseKey(winnt_key);
2323 static void delete_external_font_keys(void)
2325 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2326 DWORD dlen, vlen, datalen, valuelen, i, type;
2330 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2331 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2332 ERR("Can't create Windows font reg key\n");
2336 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2337 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2338 ERR("Can't create Windows font reg key\n");
2342 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2343 ERR("Can't create external font reg key\n");
2347 /* Delete all external fonts added last time */
2349 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2350 &valuelen, &datalen, NULL, NULL);
2351 valuelen++; /* returned value doesn't include room for '\0' */
2352 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2353 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2355 dlen = datalen * sizeof(WCHAR);
2358 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2359 &dlen) == ERROR_SUCCESS) {
2361 RegDeleteValueW(winnt_key, valueW);
2362 RegDeleteValueW(win9x_key, valueW);
2363 /* reset dlen and vlen */
2367 HeapFree(GetProcessHeap(), 0, data);
2368 HeapFree(GetProcessHeap(), 0, valueW);
2370 /* Delete the old external fonts key */
2371 RegCloseKey(external_key);
2372 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2375 if(win9x_key) RegCloseKey(win9x_key);
2376 if(winnt_key) RegCloseKey(winnt_key);
2379 /*************************************************************
2380 * WineEngAddFontResourceEx
2383 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2389 if (ft_handle) /* do it only if we have freetype up and running */
2394 FIXME("Ignoring flags %x\n", flags);
2396 if((unixname = wine_get_unix_file_name(file)))
2398 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2400 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2401 EnterCriticalSection( &freetype_cs );
2402 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2403 LeaveCriticalSection( &freetype_cs );
2404 HeapFree(GetProcessHeap(), 0, unixname);
2406 if (!ret && !strchrW(file, '\\')) {
2407 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2408 ret = load_font_from_winfonts_dir(file);
2410 /* Try in datadir/fonts (or builddir/fonts),
2411 * needed for Magic the Gathering Online
2413 ret = load_font_from_data_dir(file);
2420 /*************************************************************
2421 * WineEngAddFontMemResourceEx
2424 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2428 if (ft_handle) /* do it only if we have freetype up and running */
2430 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2432 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2433 memcpy(pFontCopy, pbFont, cbFont);
2435 EnterCriticalSection( &freetype_cs );
2436 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2437 LeaveCriticalSection( &freetype_cs );
2441 TRACE("AddFontToList failed\n");
2442 HeapFree(GetProcessHeap(), 0, pFontCopy);
2445 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2446 * For now return something unique but quite random
2448 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2449 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2456 /*************************************************************
2457 * WineEngRemoveFontResourceEx
2460 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2463 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2467 static const struct nls_update_font_list
2469 UINT ansi_cp, oem_cp;
2470 const char *oem, *fixed, *system;
2471 const char *courier, *serif, *small, *sserif;
2472 /* these are for font substitutes */
2473 const char *shelldlg, *tmsrmn;
2474 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2478 const char *from, *to;
2479 } arial_0, courier_new_0, times_new_roman_0;
2480 } nls_update_font_list[] =
2482 /* Latin 1 (United States) */
2483 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2484 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2485 "Tahoma","Times New Roman",
2486 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2489 /* Latin 1 (Multilingual) */
2490 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2491 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2492 "Tahoma","Times New Roman", /* FIXME unverified */
2493 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2496 /* Eastern Europe */
2497 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2498 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2499 "Tahoma","Times New Roman", /* FIXME unverified */
2500 "Fixedsys,238", "System,238",
2501 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2502 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2503 { "Arial CE,0", "Arial,238" },
2504 { "Courier New CE,0", "Courier New,238" },
2505 { "Times New Roman CE,0", "Times New Roman,238" }
2508 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2509 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2510 "Tahoma","Times New Roman", /* FIXME unverified */
2511 "Fixedsys,204", "System,204",
2512 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2513 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2514 { "Arial Cyr,0", "Arial,204" },
2515 { "Courier New Cyr,0", "Courier New,204" },
2516 { "Times New Roman Cyr,0", "Times New Roman,204" }
2519 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2520 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2521 "Tahoma","Times New Roman", /* FIXME unverified */
2522 "Fixedsys,161", "System,161",
2523 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2524 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2525 { "Arial Greek,0", "Arial,161" },
2526 { "Courier New Greek,0", "Courier New,161" },
2527 { "Times New Roman Greek,0", "Times New Roman,161" }
2530 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2531 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2532 "Tahoma","Times New Roman", /* FIXME unverified */
2533 "Fixedsys,162", "System,162",
2534 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2535 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2536 { "Arial Tur,0", "Arial,162" },
2537 { "Courier New Tur,0", "Courier New,162" },
2538 { "Times New Roman Tur,0", "Times New Roman,162" }
2541 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2542 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2543 "Tahoma","Times New Roman", /* FIXME unverified */
2544 "Fixedsys,177", "System,177",
2545 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2546 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2550 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2551 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2552 "Tahoma","Times New Roman", /* FIXME unverified */
2553 "Fixedsys,178", "System,178",
2554 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2555 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2559 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2560 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2561 "Tahoma","Times New Roman", /* FIXME unverified */
2562 "Fixedsys,186", "System,186",
2563 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2564 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2565 { "Arial Baltic,0", "Arial,186" },
2566 { "Courier New Baltic,0", "Courier New,186" },
2567 { "Times New Roman Baltic,0", "Times New Roman,186" }
2570 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2571 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2572 "Tahoma","Times New Roman", /* FIXME unverified */
2573 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2577 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2578 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2579 "Tahoma","Times New Roman", /* FIXME unverified */
2580 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2584 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2585 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2586 "MS UI Gothic","MS Serif",
2587 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2590 /* Chinese Simplified */
2591 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2592 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2593 "SimSun", "NSimSun",
2594 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2598 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2599 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2601 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2604 /* Chinese Traditional */
2605 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2606 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2607 "PMingLiU", "MingLiU",
2608 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2613 static const WCHAR *font_links_list[] =
2615 Lucida_Sans_Unicode,
2616 Microsoft_Sans_Serif,
2620 static const struct font_links_defaults_list
2622 /* Keyed off substitution for "MS Shell Dlg" */
2623 const WCHAR *shelldlg;
2624 /* Maximum of four substitutes, plus terminating NULL pointer */
2625 const WCHAR *substitutes[5];
2626 } font_links_defaults_list[] =
2628 /* Non East-Asian */
2629 { Tahoma, /* FIXME unverified ordering */
2630 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2632 /* Below lists are courtesy of
2633 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2637 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2639 /* Chinese Simplified */
2641 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2645 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2647 /* Chinese Traditional */
2649 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2653 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2655 return ( ansi_cp == 932 /* CP932 for Japanese */
2656 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2657 || ansi_cp == 949 /* CP949 for Korean */
2658 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2661 static inline HKEY create_fonts_NT_registry_key(void)
2665 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2666 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2670 static inline HKEY create_fonts_9x_registry_key(void)
2674 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2675 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2679 static inline HKEY create_config_fonts_registry_key(void)
2683 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2684 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2688 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2690 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2691 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2692 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2693 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2696 static void set_value_key(HKEY hkey, const char *name, const char *value)
2699 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2701 RegDeleteValueA(hkey, name);
2704 static void update_font_info(void)
2706 char buf[40], cpbuf[40];
2709 UINT i, ansi_cp = 0, oem_cp = 0;
2712 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2715 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2716 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2717 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2718 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2719 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2721 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2722 if (is_dbcs_ansi_cp(ansi_cp))
2723 use_default_fallback = TRUE;
2726 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2728 if (!strcmp( buf, cpbuf )) /* already set correctly */
2733 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2735 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2737 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2740 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2744 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2745 nls_update_font_list[i].oem_cp == oem_cp)
2747 hkey = create_config_fonts_registry_key();
2748 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2749 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2750 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2753 hkey = create_fonts_NT_registry_key();
2754 add_font_list(hkey, &nls_update_font_list[i]);
2757 hkey = create_fonts_9x_registry_key();
2758 add_font_list(hkey, &nls_update_font_list[i]);
2761 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2763 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2764 strlen(nls_update_font_list[i].shelldlg)+1);
2765 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2766 strlen(nls_update_font_list[i].tmsrmn)+1);
2768 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2769 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2770 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2771 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2772 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2773 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2774 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2775 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2777 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2778 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2779 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2787 /* Delete the FontSubstitutes from other locales */
2788 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2790 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2791 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2792 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2798 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2800 /* Clear out system links */
2801 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2804 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2814 WCHAR buff[MAX_PATH];
2818 static const WCHAR comma[] = {',',0};
2820 RegDeleteValueW(hkey, name);
2825 for (i = 0; values[i] != NULL; i++)
2828 if (!strcmpiW(name,value))
2830 psub = get_font_subst(&font_subst_list, value, -1);
2832 value = psub->to.name;
2833 family = find_family_from_name(value);
2837 /* Use first extant filename for this Family */
2838 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2842 file = strrchr(face->file, '/');
2851 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2852 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2853 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2854 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2855 if (sizeof(buff)-(data-buff) < entryLen + 1)
2857 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2858 HeapFree(GetProcessHeap(), 0, fileW);
2861 strcpyW(data, fileW);
2862 strcatW(data, comma);
2863 strcatW(data, value);
2865 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2866 HeapFree(GetProcessHeap(), 0, fileW);
2872 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2874 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2876 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2879 static void update_system_links(void)
2887 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2889 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2891 if (disposition == REG_OPENED_EXISTING_KEY)
2893 TRACE("SystemLink key already exists, doing nothing\n");
2898 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2900 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2905 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2907 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2909 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2910 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2912 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2913 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2916 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2918 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2923 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2925 WARN("failed to create SystemLink key\n");
2929 static BOOL init_freetype(void)
2931 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2934 "Wine cannot find the FreeType font library. To enable Wine to\n"
2935 "use TrueType fonts please install a version of FreeType greater than\n"
2936 "or equal to 2.0.5.\n"
2937 "http://www.freetype.org\n");
2941 #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;}
2943 LOAD_FUNCPTR(FT_Done_Face)
2944 LOAD_FUNCPTR(FT_Get_Char_Index)
2945 LOAD_FUNCPTR(FT_Get_First_Char)
2946 LOAD_FUNCPTR(FT_Get_Module)
2947 LOAD_FUNCPTR(FT_Get_Next_Char)
2948 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2949 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2950 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2951 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2952 LOAD_FUNCPTR(FT_Init_FreeType)
2953 LOAD_FUNCPTR(FT_Library_Version)
2954 LOAD_FUNCPTR(FT_Load_Glyph)
2955 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2956 LOAD_FUNCPTR(FT_Matrix_Multiply)
2957 #ifndef FT_MULFIX_INLINED
2958 LOAD_FUNCPTR(FT_MulFix)
2960 LOAD_FUNCPTR(FT_New_Face)
2961 LOAD_FUNCPTR(FT_New_Memory_Face)
2962 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2963 LOAD_FUNCPTR(FT_Outline_Transform)
2964 LOAD_FUNCPTR(FT_Outline_Translate)
2965 LOAD_FUNCPTR(FT_Render_Glyph)
2966 LOAD_FUNCPTR(FT_Select_Charmap)
2967 LOAD_FUNCPTR(FT_Set_Charmap)
2968 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2969 LOAD_FUNCPTR(FT_Vector_Transform)
2970 LOAD_FUNCPTR(FT_Vector_Unit)
2972 /* Don't warn if these ones are missing */
2973 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2974 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2975 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2978 if(pFT_Init_FreeType(&library) != 0) {
2979 ERR("Can't init FreeType library\n");
2980 wine_dlclose(ft_handle, NULL, 0);
2984 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2986 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2987 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2988 ((FT_Version.minor << 8) & 0x00ff00) |
2989 ((FT_Version.patch ) & 0x0000ff);
2991 font_driver = &freetype_funcs;
2996 "Wine cannot find certain functions that it needs inside the FreeType\n"
2997 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2998 "FreeType to at least version 2.1.4.\n"
2999 "http://www.freetype.org\n");
3000 wine_dlclose(ft_handle, NULL, 0);
3005 static void init_font_list(void)
3007 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3008 static const WCHAR pathW[] = {'P','a','t','h',0};
3010 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3011 WCHAR windowsdir[MAX_PATH];
3013 const char *data_dir;
3015 delete_external_font_keys();
3017 /* load the system bitmap fonts */
3018 load_system_fonts();
3020 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3021 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3022 strcatW(windowsdir, fontsW);
3023 if((unixname = wine_get_unix_file_name(windowsdir)))
3025 ReadFontDir(unixname, FALSE);
3026 HeapFree(GetProcessHeap(), 0, unixname);
3029 /* load the system truetype fonts */
3030 data_dir = wine_get_data_dir();
3031 if (!data_dir) data_dir = wine_get_build_dir();
3032 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3034 strcpy(unixname, data_dir);
3035 strcat(unixname, "/fonts/");
3036 ReadFontDir(unixname, TRUE);
3037 HeapFree(GetProcessHeap(), 0, unixname);
3040 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3041 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3042 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3044 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3045 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3046 &hkey) == ERROR_SUCCESS)
3048 LPWSTR data, valueW;
3049 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3050 &valuelen, &datalen, NULL, NULL);
3052 valuelen++; /* returned value doesn't include room for '\0' */
3053 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3054 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3057 dlen = datalen * sizeof(WCHAR);
3059 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3060 &dlen) == ERROR_SUCCESS)
3062 if(data[0] && (data[1] == ':'))
3064 if((unixname = wine_get_unix_file_name(data)))
3066 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3067 HeapFree(GetProcessHeap(), 0, unixname);
3070 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3072 WCHAR pathW[MAX_PATH];
3073 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3076 sprintfW(pathW, fmtW, windowsdir, data);
3077 if((unixname = wine_get_unix_file_name(pathW)))
3079 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3080 HeapFree(GetProcessHeap(), 0, unixname);
3083 load_font_from_data_dir(data);
3085 /* reset dlen and vlen */
3090 HeapFree(GetProcessHeap(), 0, data);
3091 HeapFree(GetProcessHeap(), 0, valueW);
3095 load_fontconfig_fonts();
3097 /* then look in any directories that we've specified in the config file */
3098 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3099 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3105 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3107 len += sizeof(WCHAR);
3108 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3109 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3111 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3112 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3113 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3114 TRACE( "got font path %s\n", debugstr_a(valueA) );
3118 LPSTR next = strchr( ptr, ':' );
3119 if (next) *next++ = 0;
3120 ReadFontDir( ptr, TRUE );
3123 HeapFree( GetProcessHeap(), 0, valueA );
3125 HeapFree( GetProcessHeap(), 0, valueW );
3131 static BOOL move_to_front(const WCHAR *name)
3133 Family *family, *cursor2;
3134 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3136 if(!strcmpiW(family->FamilyName, name))
3138 list_remove(&family->entry);
3139 list_add_head(&font_list, &family->entry);
3146 static BOOL set_default(const WCHAR **name_list)
3150 if (move_to_front(*name_list)) return TRUE;
3157 static void reorder_font_list(void)
3159 set_default( default_serif_list );
3160 set_default( default_fixed_list );
3161 set_default( default_sans_list );
3164 /*************************************************************
3167 * Initialize FreeType library and create a list of available faces
3169 BOOL WineEngInit(void)
3171 HKEY hkey_font_cache;
3175 /* update locale dependent font info in registry */
3178 if(!init_freetype()) return FALSE;
3180 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3182 ERR("Failed to create font mutex\n");
3185 WaitForSingleObject(font_mutex, INFINITE);
3187 create_font_cache_key(&hkey_font_cache, &disposition);
3189 if(disposition == REG_CREATED_NEW_KEY)
3192 load_font_list_from_cache(hkey_font_cache);
3194 RegCloseKey(hkey_font_cache);
3196 reorder_font_list();
3203 if(disposition == REG_CREATED_NEW_KEY)
3204 update_reg_entries();
3206 update_system_links();
3207 init_system_links();
3209 ReleaseMutex(font_mutex);
3214 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3217 TT_HoriHeader *pHori;
3221 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3222 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3224 if(height == 0) height = 16;
3226 /* Calc. height of EM square:
3228 * For +ve lfHeight we have
3229 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3230 * Re-arranging gives:
3231 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3233 * For -ve lfHeight we have
3235 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3236 * with il = winAscent + winDescent - units_per_em]
3241 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3242 ppem = MulDiv(ft_face->units_per_EM, height,
3243 pHori->Ascender - pHori->Descender);
3245 ppem = MulDiv(ft_face->units_per_EM, height,
3246 pOS2->usWinAscent + pOS2->usWinDescent);
3254 static struct font_mapping *map_font_file( const char *name )
3256 struct font_mapping *mapping;
3260 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3261 if (fstat( fd, &st ) == -1) goto error;
3263 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3265 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3267 mapping->refcount++;
3272 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3275 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3278 if (mapping->data == MAP_FAILED)
3280 HeapFree( GetProcessHeap(), 0, mapping );
3283 mapping->refcount = 1;
3284 mapping->dev = st.st_dev;
3285 mapping->ino = st.st_ino;
3286 mapping->size = st.st_size;
3287 list_add_tail( &mappings_list, &mapping->entry );
3295 static void unmap_font_file( struct font_mapping *mapping )
3297 if (!--mapping->refcount)
3299 list_remove( &mapping->entry );
3300 munmap( mapping->data, mapping->size );
3301 HeapFree( GetProcessHeap(), 0, mapping );
3305 static LONG load_VDMX(GdiFont*, LONG);
3307 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3314 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3318 if (!(font->mapping = map_font_file( face->file )))
3320 WARN("failed to map %s\n", debugstr_a(face->file));
3323 data_ptr = font->mapping->data;
3324 data_size = font->mapping->size;
3328 data_ptr = face->font_data_ptr;
3329 data_size = face->font_data_size;
3332 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3334 ERR("FT_New_Face rets %d\n", err);
3338 /* set it here, as load_VDMX needs it */
3339 font->ft_face = ft_face;
3341 if(FT_IS_SCALABLE(ft_face)) {
3342 /* load the VDMX table if we have one */
3343 font->ppem = load_VDMX(font, height);
3345 font->ppem = calc_ppem_for_height(ft_face, height);
3346 TRACE("height %d => ppem %d\n", height, font->ppem);
3348 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3349 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3351 font->ppem = height;
3352 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3353 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3359 static int get_nearest_charset(Face *face, int *cp)
3361 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3362 a single face with the requested charset. The idea is to check if
3363 the selected font supports the current ANSI codepage, if it does
3364 return the corresponding charset, else return the first charset */
3367 int acp = GetACP(), i;
3371 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3372 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3373 return csi.ciCharset;
3375 for(i = 0; i < 32; i++) {
3377 if(face->fs.fsCsb[0] & fs0) {
3378 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3380 return csi.ciCharset;
3383 FIXME("TCI failing on %x\n", fs0);
3387 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3388 face->fs.fsCsb[0], face->file);
3390 return DEFAULT_CHARSET;
3393 static GdiFont *alloc_font(void)
3395 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3397 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3398 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3400 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3401 ret->total_kern_pairs = (DWORD)-1;
3402 ret->kern_pairs = NULL;
3403 list_init(&ret->hfontlist);
3404 list_init(&ret->child_fonts);
3408 static void free_font(GdiFont *font)
3410 struct list *cursor, *cursor2;
3413 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3415 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3416 list_remove(cursor);
3418 free_font(child->font);
3419 HeapFree(GetProcessHeap(), 0, child);
3422 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3424 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3425 DeleteObject(hfontlist->hfont);
3426 list_remove(&hfontlist->entry);
3427 HeapFree(GetProcessHeap(), 0, hfontlist);
3430 if (font->ft_face) pFT_Done_Face(font->ft_face);
3431 if (font->mapping) unmap_font_file( font->mapping );
3432 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3433 HeapFree(GetProcessHeap(), 0, font->potm);
3434 HeapFree(GetProcessHeap(), 0, font->name);
3435 for (i = 0; i < font->gmsize; i++)
3436 HeapFree(GetProcessHeap(),0,font->gm[i]);
3437 HeapFree(GetProcessHeap(), 0, font->gm);
3438 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3439 HeapFree(GetProcessHeap(), 0, font);
3443 /*************************************************************
3446 * load the vdmx entry for the specified height
3449 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3450 ( ( (FT_ULong)_x4 << 24 ) | \
3451 ( (FT_ULong)_x3 << 16 ) | \
3452 ( (FT_ULong)_x2 << 8 ) | \
3455 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3470 static LONG load_VDMX(GdiFont *font, LONG height)
3474 BYTE devXRatio, devYRatio;
3475 USHORT numRecs, numRatios;
3476 DWORD result, offset = -1;
3480 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3482 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3485 /* FIXME: need the real device aspect ratio */
3489 numRecs = GET_BE_WORD(hdr[1]);
3490 numRatios = GET_BE_WORD(hdr[2]);
3492 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3493 for(i = 0; i < numRatios; i++) {
3496 offset = (3 * 2) + (i * sizeof(Ratios));
3497 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3500 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3502 if((ratio.xRatio == 0 &&
3503 ratio.yStartRatio == 0 &&
3504 ratio.yEndRatio == 0) ||
3505 (devXRatio == ratio.xRatio &&
3506 devYRatio >= ratio.yStartRatio &&
3507 devYRatio <= ratio.yEndRatio))
3509 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3510 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3511 offset = GET_BE_WORD(tmp);
3517 FIXME("No suitable ratio found\n");
3521 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3523 BYTE startsz, endsz;
3526 recs = GET_BE_WORD(group.recs);
3527 startsz = group.startsz;
3528 endsz = group.endsz;
3530 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3532 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3533 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3534 if(result == GDI_ERROR) {
3535 FIXME("Failed to retrieve vTable\n");
3540 for(i = 0; i < recs; i++) {
3541 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3542 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3543 ppem = GET_BE_WORD(vTable[i * 3]);
3545 if(yMax + -yMin == height) {
3548 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3551 if(yMax + -yMin > height) {
3554 goto end; /* failed */
3556 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3557 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3558 ppem = GET_BE_WORD(vTable[i * 3]);
3559 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3565 TRACE("ppem not found for height %d\n", height);
3569 HeapFree(GetProcessHeap(), 0, vTable);
3575 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3577 if(font->font_desc.hash != fd->hash) return TRUE;
3578 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3579 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3580 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3581 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3584 static void calc_hash(FONT_DESC *pfd)
3586 DWORD hash = 0, *ptr, two_chars;
3590 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3592 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3594 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3596 pwc = (WCHAR *)&two_chars;
3598 *pwc = toupperW(*pwc);
3600 *pwc = toupperW(*pwc);
3604 hash ^= !pfd->can_use_bitmap;
3609 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3614 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3618 fd.can_use_bitmap = can_use_bitmap;
3621 /* try the child list */
3622 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3623 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3624 if(!fontcmp(ret, &fd)) {
3625 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3626 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3627 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3628 if(hflist->hfont == hfont)
3634 /* try the in-use list */
3635 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3636 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3637 if(!fontcmp(ret, &fd)) {
3638 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3639 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3640 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3641 if(hflist->hfont == hfont)
3644 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3645 hflist->hfont = hfont;
3646 list_add_head(&ret->hfontlist, &hflist->entry);
3651 /* then the unused list */
3652 font_elem_ptr = list_head(&unused_gdi_font_list);
3653 while(font_elem_ptr) {
3654 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3655 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3656 if(!fontcmp(ret, &fd)) {
3657 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3658 assert(list_empty(&ret->hfontlist));
3659 TRACE("Found %p in unused list\n", ret);
3660 list_remove(&ret->entry);
3661 list_add_head(&gdi_font_list, &ret->entry);
3662 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3663 hflist->hfont = hfont;
3664 list_add_head(&ret->hfontlist, &hflist->entry);
3671 static void add_to_cache(GdiFont *font)
3673 static DWORD cache_num = 1;
3675 font->cache_num = cache_num++;
3676 list_add_head(&gdi_font_list, &font->entry);
3679 /*************************************************************
3680 * create_child_font_list
3682 static BOOL create_child_font_list(GdiFont *font)
3685 SYSTEM_LINKS *font_link;
3686 CHILD_FONT *font_link_entry, *new_child;
3690 psub = get_font_subst(&font_subst_list, font->name, -1);
3691 font_name = psub ? psub->to.name : font->name;
3692 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3694 if(!strcmpiW(font_link->font_name, font_name))
3696 TRACE("found entry in system list\n");
3697 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3699 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3700 new_child->face = font_link_entry->face;
3701 new_child->font = NULL;
3702 list_add_tail(&font->child_fonts, &new_child->entry);
3703 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3710 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3711 * Sans Serif. This is how asian windows get default fallbacks for fonts
3713 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3714 font->charset != OEM_CHARSET &&
3715 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3716 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3718 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3720 TRACE("found entry in default fallback list\n");
3721 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3723 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3724 new_child->face = font_link_entry->face;
3725 new_child->font = NULL;
3726 list_add_tail(&font->child_fonts, &new_child->entry);
3727 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3737 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3739 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3741 if (pFT_Set_Charmap)
3744 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3746 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3748 for (i = 0; i < ft_face->num_charmaps; i++)
3750 if (ft_face->charmaps[i]->encoding == encoding)
3752 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3753 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3755 switch (ft_face->charmaps[i]->platform_id)
3758 cmap_def = ft_face->charmaps[i];
3760 case 0: /* Apple Unicode */
3761 cmap0 = ft_face->charmaps[i];
3763 case 1: /* Macintosh */
3764 cmap1 = ft_face->charmaps[i];
3767 cmap2 = ft_face->charmaps[i];
3769 case 3: /* Microsoft */
3770 cmap3 = ft_face->charmaps[i];
3775 if (cmap3) /* prefer Microsoft cmap table */
3776 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3778 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3780 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3782 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3784 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3786 return ft_err == FT_Err_Ok;
3789 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3793 /*************************************************************
3796 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3797 LPCWSTR output, const DEVMODEW *devmode )
3799 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3801 if (!physdev) return FALSE;
3802 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3807 /*************************************************************
3810 static BOOL freetype_DeleteDC( PHYSDEV dev )
3812 struct freetype_physdev *physdev = get_freetype_dev( dev );
3813 HeapFree( GetProcessHeap(), 0, physdev );
3818 /*************************************************************
3819 * freetype_SelectFont
3821 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3823 struct freetype_physdev *physdev = get_freetype_dev( dev );
3825 Face *face, *best, *best_bitmap;
3826 Family *family, *last_resort_family;
3827 struct list *family_elem_ptr, *face_elem_ptr;
3828 INT height, width = 0;
3829 unsigned int score = 0, new_score;
3830 signed int diff = 0, newdiff;
3831 BOOL bd, it, can_use_bitmap;
3836 FontSubst *psub = NULL;
3837 DC *dc = get_dc_ptr( dev->hdc );
3839 if (!hfont) /* notification that the font has been changed by another driver */
3842 physdev->font = NULL;
3843 release_dc_ptr( dc );
3847 GetObjectW( hfont, sizeof(lf), &lf );
3848 lf.lfWidth = abs(lf.lfWidth);
3850 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3852 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3853 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3854 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3857 if(dc->GraphicsMode == GM_ADVANCED)
3858 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3861 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3862 font scaling abilities. */
3863 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3864 dcmat.eM21 = dcmat.eM12 = 0;
3867 /* Try to avoid not necessary glyph transformations */
3868 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3870 lf.lfHeight *= fabs(dcmat.eM11);
3871 lf.lfWidth *= fabs(dcmat.eM11);
3872 dcmat.eM11 = dcmat.eM22 = 1.0;
3875 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3876 dcmat.eM21, dcmat.eM22);
3879 EnterCriticalSection( &freetype_cs );
3881 /* check the cache first */
3882 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3883 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3887 if(list_empty(&font_list)) /* No fonts installed */
3889 TRACE("No fonts installed\n");
3893 TRACE("not in cache\n");
3896 ret->font_desc.matrix = dcmat;
3897 ret->font_desc.lf = lf;
3898 ret->font_desc.can_use_bitmap = can_use_bitmap;
3899 calc_hash(&ret->font_desc);
3900 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3901 hflist->hfont = hfont;
3902 list_add_head(&ret->hfontlist, &hflist->entry);
3904 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3905 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3906 original value lfCharSet. Note this is a special case for
3907 Symbol and doesn't happen at least for "Wingdings*" */
3909 if(!strcmpiW(lf.lfFaceName, SymbolW))
3910 lf.lfCharSet = SYMBOL_CHARSET;
3912 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3913 switch(lf.lfCharSet) {
3914 case DEFAULT_CHARSET:
3915 csi.fs.fsCsb[0] = 0;
3918 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3919 csi.fs.fsCsb[0] = 0;
3925 if(lf.lfFaceName[0] != '\0') {
3926 SYSTEM_LINKS *font_link;
3927 CHILD_FONT *font_link_entry;
3928 LPWSTR FaceName = lf.lfFaceName;
3931 * Check for a leading '@' this signals that the font is being
3932 * requested in tategaki mode (vertical writing substitution) but
3933 * does not affect the fontface that is to be selected.
3935 if (lf.lfFaceName[0]=='@')
3936 FaceName = &lf.lfFaceName[1];
3938 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3941 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3942 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3943 if (psub->to.charset != -1)
3944 lf.lfCharSet = psub->to.charset;
3947 /* We want a match on name and charset or just name if
3948 charset was DEFAULT_CHARSET. If the latter then
3949 we fixup the returned charset later in get_nearest_charset
3950 where we'll either use the charset of the current ansi codepage
3951 or if that's unavailable the first charset that the font supports.
3953 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3954 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3955 if (!strcmpiW(family->FamilyName, FaceName) ||
3956 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3958 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3959 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3960 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3961 if(face->scalable || can_use_bitmap)
3967 /* Search by full face name. */
3968 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3969 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3970 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3971 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3972 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3973 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3975 if(face->scalable || can_use_bitmap)
3982 * Try check the SystemLink list first for a replacement font.
3983 * We may find good replacements there.
3985 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3987 if(!strcmpiW(font_link->font_name, FaceName) ||
3988 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3990 TRACE("found entry in system list\n");
3991 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3993 face = font_link_entry->face;
3994 family = face->family;
3995 if(csi.fs.fsCsb[0] &
3996 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3998 if(face->scalable || can_use_bitmap)
4006 psub = NULL; /* substitution is no more relevant */
4008 /* If requested charset was DEFAULT_CHARSET then try using charset
4009 corresponding to the current ansi codepage */
4010 if (!csi.fs.fsCsb[0])
4013 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4014 FIXME("TCI failed on codepage %d\n", acp);
4015 csi.fs.fsCsb[0] = 0;
4017 lf.lfCharSet = csi.ciCharset;
4020 /* Face families are in the top 4 bits of lfPitchAndFamily,
4021 so mask with 0xF0 before testing */
4023 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4024 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4025 strcpyW(lf.lfFaceName, defFixed);
4026 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4027 strcpyW(lf.lfFaceName, defSerif);
4028 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4029 strcpyW(lf.lfFaceName, defSans);
4031 strcpyW(lf.lfFaceName, defSans);
4032 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4033 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4034 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4035 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4036 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4037 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4038 if(face->scalable || can_use_bitmap)
4044 last_resort_family = NULL;
4045 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4046 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4047 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4048 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4049 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4052 if(can_use_bitmap && !last_resort_family)
4053 last_resort_family = family;
4058 if(last_resort_family) {
4059 family = last_resort_family;
4060 csi.fs.fsCsb[0] = 0;
4064 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4065 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4066 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4067 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4068 if(face->scalable) {
4069 csi.fs.fsCsb[0] = 0;
4070 WARN("just using first face for now\n");
4073 if(can_use_bitmap && !last_resort_family)
4074 last_resort_family = family;
4077 if(!last_resort_family) {
4078 FIXME("can't find a single appropriate font - bailing\n");
4084 WARN("could only find a bitmap font - this will probably look awful!\n");
4085 family = last_resort_family;
4086 csi.fs.fsCsb[0] = 0;
4089 it = lf.lfItalic ? 1 : 0;
4090 bd = lf.lfWeight > 550 ? 1 : 0;
4092 height = lf.lfHeight;
4094 face = best = best_bitmap = NULL;
4095 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4097 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4101 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4102 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4103 new_score = (italic ^ it) + (bold ^ bd);
4104 if(!best || new_score <= score)
4106 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4107 italic, bold, it, bd);
4110 if(best->scalable && score == 0) break;
4114 newdiff = height - (signed int)(best->size.height);
4116 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4117 if(!best_bitmap || new_score < score ||
4118 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4120 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4123 if(score == 0 && diff == 0) break;
4130 face = best->scalable ? best : best_bitmap;
4131 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4132 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4135 height = lf.lfHeight;
4139 if(csi.fs.fsCsb[0]) {
4140 ret->charset = lf.lfCharSet;
4141 ret->codepage = csi.ciACP;
4144 ret->charset = get_nearest_charset(face, &ret->codepage);
4146 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4147 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4149 ret->aveWidth = height ? lf.lfWidth : 0;
4151 if(!face->scalable) {
4152 /* Windows uses integer scaling factors for bitmap fonts */
4153 INT scale, scaled_height;
4154 GdiFont *cachedfont;
4156 /* FIXME: rotation of bitmap fonts is ignored */
4157 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4159 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4160 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4161 dcmat.eM11 = dcmat.eM22 = 1.0;
4162 /* As we changed the matrix, we need to search the cache for the font again,
4163 * otherwise we might explode the cache. */
4164 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4165 TRACE("Found cached font after non-scalable matrix rescale!\n");
4170 calc_hash(&ret->font_desc);
4172 if (height != 0) height = diff;
4173 height += face->size.height;
4175 scale = (height + face->size.height - 1) / face->size.height;
4176 scaled_height = scale * face->size.height;
4177 /* Only jump to the next height if the difference <= 25% original height */
4178 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4179 /* The jump between unscaled and doubled is delayed by 1 */
4180 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4181 ret->scale_y = scale;
4183 width = face->size.x_ppem >> 6;
4184 height = face->size.y_ppem >> 6;
4188 TRACE("font scale y: %f\n", ret->scale_y);
4190 ret->ft_face = OpenFontFace(ret, face, width, height);
4199 ret->ntmFlags = face->ntmFlags;
4201 if (ret->charset == SYMBOL_CHARSET &&
4202 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4205 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4209 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4212 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4213 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4214 ret->underline = lf.lfUnderline ? 0xff : 0;
4215 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4216 create_child_font_list(ret);
4218 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
4220 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
4221 if (length != GDI_ERROR)
4223 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4224 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4225 TRACE("Loaded GSUB table of %i bytes\n",length);
4229 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4236 physdev->font = ret;
4238 LeaveCriticalSection( &freetype_cs );
4239 release_dc_ptr( dc );
4240 return ret ? hfont : 0;
4243 static void dump_gdi_font_list(void)
4246 struct list *elem_ptr;
4248 TRACE("---------- gdiFont Cache ----------\n");
4249 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4250 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4251 TRACE("gdiFont=%p %s %d\n",
4252 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4255 TRACE("---------- Unused gdiFont Cache ----------\n");
4256 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4257 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4258 TRACE("gdiFont=%p %s %d\n",
4259 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4262 TRACE("---------- Child gdiFont Cache ----------\n");
4263 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4264 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4265 TRACE("gdiFont=%p %s %d\n",
4266 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4270 /*************************************************************
4271 * WineEngDestroyFontInstance
4273 * free the gdiFont associated with this handle
4276 BOOL WineEngDestroyFontInstance(HFONT handle)
4281 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4285 EnterCriticalSection( &freetype_cs );
4287 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4289 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4290 while(hfontlist_elem_ptr) {
4291 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4292 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4293 if(hflist->hfont == handle) {
4294 TRACE("removing child font %p from child list\n", gdiFont);
4295 list_remove(&gdiFont->entry);
4296 LeaveCriticalSection( &freetype_cs );
4302 TRACE("destroying hfont=%p\n", handle);
4304 dump_gdi_font_list();
4306 font_elem_ptr = list_head(&gdi_font_list);
4307 while(font_elem_ptr) {
4308 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4309 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4311 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4312 while(hfontlist_elem_ptr) {
4313 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4314 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4315 if(hflist->hfont == handle) {
4316 list_remove(&hflist->entry);
4317 HeapFree(GetProcessHeap(), 0, hflist);
4321 if(list_empty(&gdiFont->hfontlist)) {
4322 TRACE("Moving to Unused list\n");
4323 list_remove(&gdiFont->entry);
4324 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4329 font_elem_ptr = list_head(&unused_gdi_font_list);
4330 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4331 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4332 while(font_elem_ptr) {
4333 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4334 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4335 TRACE("freeing %p\n", gdiFont);
4336 list_remove(&gdiFont->entry);
4339 LeaveCriticalSection( &freetype_cs );
4343 /***************************************************
4344 * create_enum_charset_list
4346 * This function creates charset enumeration list because in DEFAULT_CHARSET
4347 * case, the ANSI codepage's charset takes precedence over other charsets.
4348 * This function works as a filter other than DEFAULT_CHARSET case.
4350 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4355 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4356 csi.fs.fsCsb[0] != 0) {
4357 list->element[n].mask = csi.fs.fsCsb[0];
4358 list->element[n].charset = csi.ciCharset;
4359 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4362 else { /* charset is DEFAULT_CHARSET or invalid. */
4365 /* Set the current codepage's charset as the first element. */
4367 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4368 csi.fs.fsCsb[0] != 0) {
4369 list->element[n].mask = csi.fs.fsCsb[0];
4370 list->element[n].charset = csi.ciCharset;
4371 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4375 /* Fill out left elements. */
4376 for (i = 0; i < 32; i++) {
4378 fs.fsCsb[0] = 1L << i;
4380 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4381 continue; /* skip, already added. */
4382 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4383 continue; /* skip, this is an invalid fsCsb bit. */
4385 list->element[n].mask = fs.fsCsb[0];
4386 list->element[n].charset = csi.ciCharset;
4387 list->element[n].name = ElfScriptsW[i];
4396 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4397 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4402 if (face->cached_enum_data)
4405 *pelf = face->cached_enum_data->elf;
4406 *pntm = face->cached_enum_data->ntm;
4407 *ptype = face->cached_enum_data->type;
4411 font = alloc_font();
4413 if(face->scalable) {
4414 height = -2048; /* 2048 is the most common em size */
4417 height = face->size.y_ppem >> 6;
4418 width = face->size.x_ppem >> 6;
4420 font->scale_y = 1.0;
4422 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4428 font->name = strdupW(face->family->FamilyName);
4429 font->ntmFlags = face->ntmFlags;
4431 if (get_outline_text_metrics(font))
4433 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4435 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4437 lstrcpynW(pelf->elfLogFont.lfFaceName,
4438 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4440 lstrcpynW(pelf->elfFullName,
4441 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4443 lstrcpynW(pelf->elfStyle,
4444 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4449 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4451 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4453 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4455 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4457 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4458 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4461 pntm->ntmTm.ntmFlags = face->ntmFlags;
4462 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4463 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4464 pntm->ntmFontSig = face->fs;
4466 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4468 pelf->elfLogFont.lfEscapement = 0;
4469 pelf->elfLogFont.lfOrientation = 0;
4470 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4471 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4472 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4473 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4474 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4475 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4476 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4477 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4478 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4479 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4480 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4483 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4484 *ptype |= TRUETYPE_FONTTYPE;
4485 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4486 *ptype |= DEVICE_FONTTYPE;
4487 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4488 *ptype |= RASTER_FONTTYPE;
4490 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4491 if (face->cached_enum_data)
4493 face->cached_enum_data->elf = *pelf;
4494 face->cached_enum_data->ntm = *pntm;
4495 face->cached_enum_data->type = *ptype;
4501 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4503 struct list *face_elem_ptr;
4505 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4507 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4509 static const WCHAR spaceW[] = { ' ',0 };
4510 WCHAR full_family_name[LF_FULLFACESIZE];
4511 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4513 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4515 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4516 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4520 strcpyW(full_family_name, family->FamilyName);
4521 strcatW(full_family_name, spaceW);
4522 strcatW(full_family_name, face->StyleName);
4523 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4529 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4531 static const WCHAR spaceW[] = { ' ',0 };
4532 WCHAR full_family_name[LF_FULLFACESIZE];
4534 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4536 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4538 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4539 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4543 strcpyW(full_family_name, face->family->FamilyName);
4544 strcatW(full_family_name, spaceW);
4545 strcatW(full_family_name, face->StyleName);
4546 return !strcmpiW(lf->lfFaceName, full_family_name);
4549 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4550 FONTENUMPROCW proc, LPARAM lparam)
4553 NEWTEXTMETRICEXW ntm;
4557 GetEnumStructs(face, &elf, &ntm, &type);
4558 for(i = 0; i < list->total; i++) {
4559 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4560 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4561 strcpyW(elf.elfScript, OEM_DOSW);
4562 i = 32; /* break out of loop */
4563 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4566 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4567 if(list->element[i].name)
4568 strcpyW(elf.elfScript, list->element[i].name);
4570 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4572 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4573 debugstr_w(elf.elfLogFont.lfFaceName),
4574 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4575 list->element[i].charset, type, debugstr_w(elf.elfScript),
4576 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4577 ntm.ntmTm.ntmFlags);
4578 /* release section before callback (FIXME) */
4579 LeaveCriticalSection( &freetype_cs );
4580 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4581 EnterCriticalSection( &freetype_cs );
4586 /*************************************************************
4587 * freetype_EnumFonts
4589 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4593 struct list *family_elem_ptr, *face_elem_ptr;
4595 struct enum_charset_list enum_charsets;
4599 lf.lfCharSet = DEFAULT_CHARSET;
4600 lf.lfPitchAndFamily = 0;
4601 lf.lfFaceName[0] = 0;
4605 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4607 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4610 EnterCriticalSection( &freetype_cs );
4611 if(plf->lfFaceName[0]) {
4613 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4616 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4617 debugstr_w(psub->to.name));
4619 strcpyW(lf.lfFaceName, psub->to.name);
4623 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4624 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4625 if(family_matches(family, plf)) {
4626 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4627 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4628 if (!face_matches(face, plf)) continue;
4629 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4634 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4635 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4636 face_elem_ptr = list_head(&family->faces);
4637 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4638 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4641 LeaveCriticalSection( &freetype_cs );
4645 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4647 pt->x.value = vec->x >> 6;
4648 pt->x.fract = (vec->x & 0x3f) << 10;
4649 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4650 pt->y.value = vec->y >> 6;
4651 pt->y.fract = (vec->y & 0x3f) << 10;
4652 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4656 /***************************************************
4657 * According to the MSDN documentation on WideCharToMultiByte,
4658 * certain codepages cannot set the default_used parameter.
4659 * This returns TRUE if the codepage can set that parameter, false else
4660 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4662 static BOOL codepage_sets_default_used(UINT codepage)
4676 * GSUB Table handling functions
4679 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4681 const GSUB_CoverageFormat1* cf1;
4685 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4687 int count = GET_BE_WORD(cf1->GlyphCount);
4689 TRACE("Coverage Format 1, %i glyphs\n",count);
4690 for (i = 0; i < count; i++)
4691 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4695 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4697 const GSUB_CoverageFormat2* cf2;
4700 cf2 = (const GSUB_CoverageFormat2*)cf1;
4702 count = GET_BE_WORD(cf2->RangeCount);
4703 TRACE("Coverage Format 2, %i ranges\n",count);
4704 for (i = 0; i < count; i++)
4706 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4708 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4709 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4711 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4712 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4718 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4723 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4725 const GSUB_ScriptList *script;
4726 const GSUB_Script *deflt = NULL;
4728 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4730 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4731 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4733 const GSUB_Script *scr;
4736 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4737 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4739 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4741 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4747 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4751 const GSUB_LangSys *Lang;
4753 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4755 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4757 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4758 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4760 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4763 offset = GET_BE_WORD(script->DefaultLangSys);
4766 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4772 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4775 const GSUB_FeatureList *feature;
4776 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4778 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4779 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4781 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4782 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4784 const GSUB_Feature *feat;
4785 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4792 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4796 const GSUB_LookupList *lookup;
4797 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4799 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4800 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4802 const GSUB_LookupTable *look;
4803 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4804 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4805 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4806 if (GET_BE_WORD(look->LookupType) != 1)
4807 FIXME("We only handle SubType 1\n");
4812 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4814 const GSUB_SingleSubstFormat1 *ssf1;
4815 offset = GET_BE_WORD(look->SubTable[j]);
4816 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4817 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4819 int offset = GET_BE_WORD(ssf1->Coverage);
4820 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4821 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4823 TRACE(" Glyph 0x%x ->",glyph);
4824 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4825 TRACE(" 0x%x\n",glyph);
4830 const GSUB_SingleSubstFormat2 *ssf2;
4834 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4835 offset = GET_BE_WORD(ssf1->Coverage);
4836 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4837 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4838 TRACE(" Coverage index %i\n",index);
4841 TRACE(" Glyph is 0x%x ->",glyph);
4842 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4843 TRACE("0x%x\n",glyph);
4852 static const char* get_opentype_script(const GdiFont *font)
4855 * I am not sure if this is the correct way to generate our script tag
4858 switch (font->charset)
4860 case ANSI_CHARSET: return "latn";
4861 case BALTIC_CHARSET: return "latn"; /* ?? */
4862 case CHINESEBIG5_CHARSET: return "hani";
4863 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4864 case GB2312_CHARSET: return "hani";
4865 case GREEK_CHARSET: return "grek";
4866 case HANGUL_CHARSET: return "hang";
4867 case RUSSIAN_CHARSET: return "cyrl";
4868 case SHIFTJIS_CHARSET: return "kana";
4869 case TURKISH_CHARSET: return "latn"; /* ?? */
4870 case VIETNAMESE_CHARSET: return "latn";
4871 case JOHAB_CHARSET: return "latn"; /* ?? */
4872 case ARABIC_CHARSET: return "arab";
4873 case HEBREW_CHARSET: return "hebr";
4874 case THAI_CHARSET: return "thai";
4875 default: return "latn";
4879 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4881 const GSUB_Header *header;
4882 const GSUB_Script *script;
4883 const GSUB_LangSys *language;
4884 const GSUB_Feature *feature;
4886 if (!font->GSUB_Table)
4889 header = font->GSUB_Table;
4891 script = GSUB_get_script_table(header, get_opentype_script(font));
4894 TRACE("Script not found\n");
4897 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4900 TRACE("Language not found\n");
4903 feature = GSUB_get_feature(header, language, "vrt2");
4905 feature = GSUB_get_feature(header, language, "vert");
4908 TRACE("vrt2/vert feature not found\n");
4911 return GSUB_apply_feature(header, feature, glyph);
4914 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4918 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4919 WCHAR wc = (WCHAR)glyph;
4921 BOOL *default_used_pointer;
4924 default_used_pointer = NULL;
4925 default_used = FALSE;
4926 if (codepage_sets_default_used(font->codepage))
4927 default_used_pointer = &default_used;
4928 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4931 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4932 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4933 return get_GSUB_vert_glyph(font,ret);
4936 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4938 if (glyph < 0x100) glyph += 0xf000;
4939 /* there is a number of old pre-Unicode "broken" TTFs, which
4940 do have symbols at U+00XX instead of U+f0XX */
4941 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4942 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4944 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4946 return get_GSUB_vert_glyph(font,glyphId);
4949 /*************************************************************
4950 * WineEngGetGlyphIndices
4953 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4954 LPWORD pgi, DWORD flags)
4958 BOOL got_default = FALSE;
4960 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4962 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4967 EnterCriticalSection( &freetype_cs );
4969 for(i = 0; i < count; i++)
4971 pgi[i] = get_glyph_index(font, lpstr[i]);
4976 if (FT_IS_SFNT(font->ft_face))
4978 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4979 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4984 get_text_metrics(font, &textm);
4985 default_char = textm.tmDefaultChar;
4989 pgi[i] = default_char;
4992 LeaveCriticalSection( &freetype_cs );
4996 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4998 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4999 return !memcmp(matrix, &identity, sizeof(FMAT2));
5002 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5004 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5005 return !memcmp(matrix, &identity, sizeof(MAT2));
5008 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5009 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5012 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5013 FT_Face ft_face = incoming_font->ft_face;
5014 GdiFont *font = incoming_font;
5015 FT_UInt glyph_index;
5016 DWORD width, height, pitch, needed = 0;
5017 FT_Bitmap ft_bitmap;
5019 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5021 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5022 double widthRatio = 1.0;
5023 FT_Matrix transMat = identityMat;
5024 FT_Matrix transMatUnrotated;
5025 BOOL needsTransform = FALSE;
5026 BOOL tategaki = (font->GSUB_Table != NULL);
5027 UINT original_index;
5029 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5030 buflen, buf, lpmat);
5032 TRACE("font transform %f %f %f %f\n",
5033 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5034 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5036 if(format & GGO_GLYPH_INDEX) {
5037 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5038 original_index = glyph;
5039 format &= ~GGO_GLYPH_INDEX;
5041 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5042 ft_face = font->ft_face;
5043 original_index = glyph_index;
5046 if(format & GGO_UNHINTED) {
5047 load_flags |= FT_LOAD_NO_HINTING;
5048 format &= ~GGO_UNHINTED;
5051 /* tategaki never appears to happen to lower glyph index */
5052 if (glyph_index < TATEGAKI_LOWER_BOUND )
5055 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5056 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5057 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5058 font->gmsize * sizeof(GM*));
5060 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5061 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5063 *lpgm = FONT_GM(font,original_index)->gm;
5064 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5065 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5066 lpgm->gmCellIncX, lpgm->gmCellIncY);
5067 return 1; /* FIXME */
5071 if (!font->gm[original_index / GM_BLOCK_SIZE])
5072 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5074 /* Scaling factor */
5079 get_text_metrics(font, &tm);
5081 widthRatio = (double)font->aveWidth;
5082 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5085 widthRatio = font->scale_y;
5087 /* Scaling transform */
5088 if (widthRatio != 1.0 || font->scale_y != 1.0)
5091 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5094 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5096 pFT_Matrix_Multiply(&scaleMat, &transMat);
5097 needsTransform = TRUE;
5100 /* Slant transform */
5101 if (font->fake_italic) {
5104 slantMat.xx = (1 << 16);
5105 slantMat.xy = ((1 << 16) >> 2);
5107 slantMat.yy = (1 << 16);
5108 pFT_Matrix_Multiply(&slantMat, &transMat);
5109 needsTransform = TRUE;
5112 /* Rotation transform */
5113 transMatUnrotated = transMat;
5114 if(font->orientation && !tategaki) {
5115 FT_Matrix rotationMat;
5117 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5118 pFT_Vector_Unit(&vecAngle, angle);
5119 rotationMat.xx = vecAngle.x;
5120 rotationMat.xy = -vecAngle.y;
5121 rotationMat.yx = -rotationMat.xy;
5122 rotationMat.yy = rotationMat.xx;
5124 pFT_Matrix_Multiply(&rotationMat, &transMat);
5125 needsTransform = TRUE;
5128 /* World transform */
5129 if (!is_identity_FMAT2(&font->font_desc.matrix))
5132 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5133 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5134 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5135 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5136 pFT_Matrix_Multiply(&worldMat, &transMat);
5137 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5138 needsTransform = TRUE;
5141 /* Extra transformation specified by caller */
5142 if (!is_identity_MAT2(lpmat))
5145 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5146 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5147 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5148 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5149 pFT_Matrix_Multiply(&extraMat, &transMat);
5150 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5151 needsTransform = TRUE;
5154 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5155 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5156 format == GGO_GRAY8_BITMAP))
5158 load_flags |= FT_LOAD_NO_BITMAP;
5161 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5164 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5168 if(!needsTransform) {
5169 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5170 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5171 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5173 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5174 bottom = (ft_face->glyph->metrics.horiBearingY -
5175 ft_face->glyph->metrics.height) & -64;
5176 lpgm->gmCellIncX = adv;
5177 lpgm->gmCellIncY = 0;
5184 for(xc = 0; xc < 2; xc++) {
5185 for(yc = 0; yc < 2; yc++) {
5186 vec.x = (ft_face->glyph->metrics.horiBearingX +
5187 xc * ft_face->glyph->metrics.width);
5188 vec.y = ft_face->glyph->metrics.horiBearingY -
5189 yc * ft_face->glyph->metrics.height;
5190 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5191 pFT_Vector_Transform(&vec, &transMat);
5192 if(xc == 0 && yc == 0) {
5193 left = right = vec.x;
5194 top = bottom = vec.y;
5196 if(vec.x < left) left = vec.x;
5197 else if(vec.x > right) right = vec.x;
5198 if(vec.y < bottom) bottom = vec.y;
5199 else if(vec.y > top) top = vec.y;
5204 right = (right + 63) & -64;
5205 bottom = bottom & -64;
5206 top = (top + 63) & -64;
5208 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5209 vec.x = ft_face->glyph->metrics.horiAdvance;
5211 pFT_Vector_Transform(&vec, &transMat);
5212 lpgm->gmCellIncX = (vec.x+63) >> 6;
5213 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5215 vec.x = ft_face->glyph->metrics.horiAdvance;
5217 pFT_Vector_Transform(&vec, &transMatUnrotated);
5218 adv = (vec.x+63) >> 6;
5222 bbx = (right - left) >> 6;
5223 lpgm->gmBlackBoxX = (right - left) >> 6;
5224 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5225 lpgm->gmptGlyphOrigin.x = left >> 6;
5226 lpgm->gmptGlyphOrigin.y = top >> 6;
5228 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5229 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5230 lpgm->gmCellIncX, lpgm->gmCellIncY);
5232 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5233 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5235 FONT_GM(font,original_index)->gm = *lpgm;
5236 FONT_GM(font,original_index)->adv = adv;
5237 FONT_GM(font,original_index)->lsb = lsb;
5238 FONT_GM(font,original_index)->bbx = bbx;
5239 FONT_GM(font,original_index)->init = TRUE;
5242 if(format == GGO_METRICS)
5244 return 1; /* FIXME */
5247 if(ft_face->glyph->format != ft_glyph_format_outline &&
5248 (format == GGO_NATIVE || format == GGO_BEZIER ||
5249 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5250 format == GGO_GRAY8_BITMAP))
5252 TRACE("loaded a bitmap\n");
5258 width = lpgm->gmBlackBoxX;
5259 height = lpgm->gmBlackBoxY;
5260 pitch = ((width + 31) >> 5) << 2;
5261 needed = pitch * height;
5263 if(!buf || !buflen) break;
5265 switch(ft_face->glyph->format) {
5266 case ft_glyph_format_bitmap:
5268 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5269 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5270 INT h = ft_face->glyph->bitmap.rows;
5272 memcpy(dst, src, w);
5273 src += ft_face->glyph->bitmap.pitch;
5279 case ft_glyph_format_outline:
5280 ft_bitmap.width = width;
5281 ft_bitmap.rows = height;
5282 ft_bitmap.pitch = pitch;
5283 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5284 ft_bitmap.buffer = buf;
5287 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5289 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5291 /* Note: FreeType will only set 'black' bits for us. */
5292 memset(buf, 0, needed);
5293 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5297 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5302 case GGO_GRAY2_BITMAP:
5303 case GGO_GRAY4_BITMAP:
5304 case GGO_GRAY8_BITMAP:
5305 case WINE_GGO_GRAY16_BITMAP:
5307 unsigned int mult, row, col;
5310 width = lpgm->gmBlackBoxX;
5311 height = lpgm->gmBlackBoxY;
5312 pitch = (width + 3) / 4 * 4;
5313 needed = pitch * height;
5315 if(!buf || !buflen) break;
5317 switch(ft_face->glyph->format) {
5318 case ft_glyph_format_bitmap:
5320 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5321 INT h = ft_face->glyph->bitmap.rows;
5323 memset( buf, 0, needed );
5325 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5326 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
5327 src += ft_face->glyph->bitmap.pitch;
5332 case ft_glyph_format_outline:
5334 ft_bitmap.width = width;
5335 ft_bitmap.rows = height;
5336 ft_bitmap.pitch = pitch;
5337 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5338 ft_bitmap.buffer = buf;
5341 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5343 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5345 memset(ft_bitmap.buffer, 0, buflen);
5347 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5349 if(format == GGO_GRAY2_BITMAP)
5351 else if(format == GGO_GRAY4_BITMAP)
5353 else if(format == GGO_GRAY8_BITMAP)
5355 else /* format == WINE_GGO_GRAY16_BITMAP */
5360 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5365 for(row = 0; row < height; row++) {
5367 for(col = 0; col < width; col++, ptr++) {
5368 *ptr = (((int)*ptr) * mult + 128) / 256;
5375 case WINE_GGO_HRGB_BITMAP:
5376 case WINE_GGO_HBGR_BITMAP:
5377 case WINE_GGO_VRGB_BITMAP:
5378 case WINE_GGO_VBGR_BITMAP:
5379 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5381 switch (ft_face->glyph->format)
5383 case FT_GLYPH_FORMAT_BITMAP:
5388 width = lpgm->gmBlackBoxX;
5389 height = lpgm->gmBlackBoxY;
5391 needed = pitch * height;
5393 if (!buf || !buflen) break;
5395 memset(buf, 0, buflen);
5397 src = ft_face->glyph->bitmap.buffer;
5398 src_pitch = ft_face->glyph->bitmap.pitch;
5400 height = min( height, ft_face->glyph->bitmap.rows );
5403 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5405 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5406 ((unsigned int *)dst)[x] = ~0u;
5415 case FT_GLYPH_FORMAT_OUTLINE:
5419 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5420 INT x_shift, y_shift;
5422 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5423 FT_Render_Mode render_mode =
5424 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5425 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5427 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5429 if ( render_mode == FT_RENDER_MODE_LCD)
5431 lpgm->gmBlackBoxX += 2;
5432 lpgm->gmptGlyphOrigin.x -= 1;
5436 lpgm->gmBlackBoxY += 2;
5437 lpgm->gmptGlyphOrigin.y += 1;
5441 width = lpgm->gmBlackBoxX;
5442 height = lpgm->gmBlackBoxY;
5444 needed = pitch * height;
5446 if (!buf || !buflen) break;
5448 memset(buf, 0, buflen);
5450 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5452 if ( needsTransform )
5453 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5455 if ( pFT_Library_SetLcdFilter )
5456 pFT_Library_SetLcdFilter( library, lcdfilter );
5457 pFT_Render_Glyph (ft_face->glyph, render_mode);
5459 src = ft_face->glyph->bitmap.buffer;
5460 src_pitch = ft_face->glyph->bitmap.pitch;
5461 src_width = ft_face->glyph->bitmap.width;
5462 src_height = ft_face->glyph->bitmap.rows;
5464 if ( render_mode == FT_RENDER_MODE_LCD)
5472 rgb_interval = src_pitch;
5477 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5478 if ( x_shift < 0 ) x_shift = 0;
5479 if ( x_shift + (src_width / hmul) > width )
5480 x_shift = width - (src_width / hmul);
5482 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5483 if ( y_shift < 0 ) y_shift = 0;
5484 if ( y_shift + (src_height / vmul) > height )
5485 y_shift = height - (src_height / vmul);
5487 dst += x_shift + y_shift * ( pitch / 4 );
5488 while ( src_height )
5490 for ( x = 0; x < src_width / hmul; x++ )
5494 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5495 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5496 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5497 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5501 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5502 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5503 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5504 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5507 src += src_pitch * vmul;
5516 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5528 int contour, point = 0, first_pt;
5529 FT_Outline *outline = &ft_face->glyph->outline;
5530 TTPOLYGONHEADER *pph;
5532 DWORD pph_start, cpfx, type;
5534 if(buflen == 0) buf = NULL;
5536 if (needsTransform && buf) {
5537 pFT_Outline_Transform(outline, &transMat);
5540 for(contour = 0; contour < outline->n_contours; contour++) {
5542 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5545 pph->dwType = TT_POLYGON_TYPE;
5546 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5548 needed += sizeof(*pph);
5550 while(point <= outline->contours[contour]) {
5551 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5552 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5553 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5557 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5560 } while(point <= outline->contours[contour] &&
5561 (outline->tags[point] & FT_Curve_Tag_On) ==
5562 (outline->tags[point-1] & FT_Curve_Tag_On));
5563 /* At the end of a contour Windows adds the start point, but
5565 if(point > outline->contours[contour] &&
5566 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5568 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5570 } else if(point <= outline->contours[contour] &&
5571 outline->tags[point] & FT_Curve_Tag_On) {
5572 /* add closing pt for bezier */
5574 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5582 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5585 pph->cb = needed - pph_start;
5591 /* Convert the quadratic Beziers to cubic Beziers.
5592 The parametric eqn for a cubic Bezier is, from PLRM:
5593 r(t) = at^3 + bt^2 + ct + r0
5594 with the control points:
5599 A quadratic Bezier has the form:
5600 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5602 So equating powers of t leads to:
5603 r1 = 2/3 p1 + 1/3 p0
5604 r2 = 2/3 p1 + 1/3 p2
5605 and of course r0 = p0, r3 = p2
5608 int contour, point = 0, first_pt;
5609 FT_Outline *outline = &ft_face->glyph->outline;
5610 TTPOLYGONHEADER *pph;
5612 DWORD pph_start, cpfx, type;
5613 FT_Vector cubic_control[4];
5614 if(buflen == 0) buf = NULL;
5616 if (needsTransform && buf) {
5617 pFT_Outline_Transform(outline, &transMat);
5620 for(contour = 0; contour < outline->n_contours; contour++) {
5622 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5625 pph->dwType = TT_POLYGON_TYPE;
5626 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5628 needed += sizeof(*pph);
5630 while(point <= outline->contours[contour]) {
5631 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5632 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5633 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5636 if(type == TT_PRIM_LINE) {
5638 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5642 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5645 /* FIXME: Possible optimization in endpoint calculation
5646 if there are two consecutive curves */
5647 cubic_control[0] = outline->points[point-1];
5648 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5649 cubic_control[0].x += outline->points[point].x + 1;
5650 cubic_control[0].y += outline->points[point].y + 1;
5651 cubic_control[0].x >>= 1;
5652 cubic_control[0].y >>= 1;
5654 if(point+1 > outline->contours[contour])
5655 cubic_control[3] = outline->points[first_pt];
5657 cubic_control[3] = outline->points[point+1];
5658 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5659 cubic_control[3].x += outline->points[point].x + 1;
5660 cubic_control[3].y += outline->points[point].y + 1;
5661 cubic_control[3].x >>= 1;
5662 cubic_control[3].y >>= 1;
5665 /* r1 = 1/3 p0 + 2/3 p1
5666 r2 = 1/3 p2 + 2/3 p1 */
5667 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5668 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5669 cubic_control[2] = cubic_control[1];
5670 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5671 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5672 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5673 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5675 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5676 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5677 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5682 } while(point <= outline->contours[contour] &&
5683 (outline->tags[point] & FT_Curve_Tag_On) ==
5684 (outline->tags[point-1] & FT_Curve_Tag_On));
5685 /* At the end of a contour Windows adds the start point,
5686 but only for Beziers and we've already done that.
5688 if(point <= outline->contours[contour] &&
5689 outline->tags[point] & FT_Curve_Tag_On) {
5690 /* This is the closing pt of a bezier, but we've already
5691 added it, so just inc point and carry on */
5698 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5701 pph->cb = needed - pph_start;
5707 FIXME("Unsupported format %d\n", format);
5713 static BOOL get_bitmap_text_metrics(GdiFont *font)
5715 FT_Face ft_face = font->ft_face;
5716 FT_WinFNT_HeaderRec winfnt_header;
5717 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5718 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5719 font->potm->otmSize = size;
5721 #define TM font->potm->otmTextMetrics
5722 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5724 TM.tmHeight = winfnt_header.pixel_height;
5725 TM.tmAscent = winfnt_header.ascent;
5726 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5727 TM.tmInternalLeading = winfnt_header.internal_leading;
5728 TM.tmExternalLeading = winfnt_header.external_leading;
5729 TM.tmAveCharWidth = winfnt_header.avg_width;
5730 TM.tmMaxCharWidth = winfnt_header.max_width;
5731 TM.tmWeight = winfnt_header.weight;
5733 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5734 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5735 TM.tmFirstChar = winfnt_header.first_char;
5736 TM.tmLastChar = winfnt_header.last_char;
5737 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5738 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5739 TM.tmItalic = winfnt_header.italic;
5740 TM.tmUnderlined = font->underline;
5741 TM.tmStruckOut = font->strikeout;
5742 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5743 TM.tmCharSet = winfnt_header.charset;
5747 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5748 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5749 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5750 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5751 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5752 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5753 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5754 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5756 TM.tmDigitizedAspectX = 96; /* FIXME */
5757 TM.tmDigitizedAspectY = 96; /* FIXME */
5759 TM.tmLastChar = 255;
5760 TM.tmDefaultChar = 32;
5761 TM.tmBreakChar = 32;
5762 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5763 TM.tmUnderlined = font->underline;
5764 TM.tmStruckOut = font->strikeout;
5765 /* NB inverted meaning of TMPF_FIXED_PITCH */
5766 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5767 TM.tmCharSet = font->charset;
5775 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5777 double scale_x, scale_y;
5781 scale_x = (double)font->aveWidth;
5782 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5785 scale_x = font->scale_y;
5787 scale_x *= fabs(font->font_desc.matrix.eM11);
5788 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
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(ptm->tmHeight);
5794 SCALE_Y(ptm->tmAscent);
5795 SCALE_Y(ptm->tmDescent);
5796 SCALE_Y(ptm->tmInternalLeading);
5797 SCALE_Y(ptm->tmExternalLeading);
5798 SCALE_Y(ptm->tmOverhang);
5800 SCALE_X(ptm->tmAveCharWidth);
5801 SCALE_X(ptm->tmMaxCharWidth);
5807 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5809 double scale_x, scale_y;
5813 scale_x = (double)font->aveWidth;
5814 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5817 scale_x = font->scale_y;
5819 scale_x *= fabs(font->font_desc.matrix.eM11);
5820 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5822 scale_font_metrics(font, &potm->otmTextMetrics);
5824 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5825 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5827 SCALE_Y(potm->otmAscent);
5828 SCALE_Y(potm->otmDescent);
5829 SCALE_Y(potm->otmLineGap);
5830 SCALE_Y(potm->otmsCapEmHeight);
5831 SCALE_Y(potm->otmsXHeight);
5832 SCALE_Y(potm->otmrcFontBox.top);
5833 SCALE_Y(potm->otmrcFontBox.bottom);
5834 SCALE_X(potm->otmrcFontBox.left);
5835 SCALE_X(potm->otmrcFontBox.right);
5836 SCALE_Y(potm->otmMacAscent);
5837 SCALE_Y(potm->otmMacDescent);
5838 SCALE_Y(potm->otmMacLineGap);
5839 SCALE_X(potm->otmptSubscriptSize.x);
5840 SCALE_Y(potm->otmptSubscriptSize.y);
5841 SCALE_X(potm->otmptSubscriptOffset.x);
5842 SCALE_Y(potm->otmptSubscriptOffset.y);
5843 SCALE_X(potm->otmptSuperscriptSize.x);
5844 SCALE_Y(potm->otmptSuperscriptSize.y);
5845 SCALE_X(potm->otmptSuperscriptOffset.x);
5846 SCALE_Y(potm->otmptSuperscriptOffset.y);
5847 SCALE_Y(potm->otmsStrikeoutSize);
5848 SCALE_Y(potm->otmsStrikeoutPosition);
5849 SCALE_Y(potm->otmsUnderscoreSize);
5850 SCALE_Y(potm->otmsUnderscorePosition);
5856 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5860 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5862 /* Make sure that the font has sane width/height ratio */
5865 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5867 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5872 *ptm = font->potm->otmTextMetrics;
5873 scale_font_metrics(font, ptm);
5877 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5881 for(i = 0; i < ft_face->num_charmaps; i++)
5883 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5889 static BOOL get_outline_text_metrics(GdiFont *font)
5892 FT_Face ft_face = font->ft_face;
5893 UINT needed, lenfam, lensty;
5895 TT_HoriHeader *pHori;
5896 TT_Postscript *pPost;
5897 FT_Fixed x_scale, y_scale;
5898 WCHAR *family_nameW, *style_nameW;
5899 static const WCHAR spaceW[] = {' ', '\0'};
5901 INT ascent, descent;
5903 TRACE("font=%p\n", font);
5905 if(!FT_IS_SCALABLE(ft_face))
5908 needed = sizeof(*font->potm);
5910 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5911 family_nameW = strdupW(font->name);
5913 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5915 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5916 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5917 style_nameW, lensty/sizeof(WCHAR));
5919 /* These names should be read from the TT name table */
5921 /* length of otmpFamilyName */
5924 /* length of otmpFaceName */
5925 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5926 needed += lenfam; /* just the family name */
5928 needed += lenfam + lensty; /* family + " " + style */
5931 /* length of otmpStyleName */
5934 /* length of otmpFullName */
5935 needed += lenfam + lensty;
5938 x_scale = ft_face->size->metrics.x_scale;
5939 y_scale = ft_face->size->metrics.y_scale;
5941 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5943 FIXME("Can't find OS/2 table - not TT font?\n");
5947 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5949 FIXME("Can't find HHEA table - not TT font?\n");
5953 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5955 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",
5956 pOS2->usWinAscent, pOS2->usWinDescent,
5957 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5958 ft_face->ascender, ft_face->descender, ft_face->height,
5959 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5960 ft_face->bbox.yMax, ft_face->bbox.yMin);
5962 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5963 font->potm->otmSize = needed;
5965 #define TM font->potm->otmTextMetrics
5967 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5968 ascent = pHori->Ascender;
5969 descent = -pHori->Descender;
5971 ascent = pOS2->usWinAscent;
5972 descent = pOS2->usWinDescent;
5976 TM.tmAscent = font->yMax;
5977 TM.tmDescent = -font->yMin;
5978 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5980 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5981 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5982 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5983 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5986 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5989 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5991 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5992 ((ascent + descent) -
5993 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5995 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5996 if (TM.tmAveCharWidth == 0) {
5997 TM.tmAveCharWidth = 1;
5999 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6000 TM.tmWeight = FW_REGULAR;
6001 if (font->fake_bold)
6002 TM.tmWeight = FW_BOLD;
6005 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6007 if (pOS2->usWeightClass > FW_MEDIUM)
6008 TM.tmWeight = pOS2->usWeightClass;
6010 else if (pOS2->usWeightClass <= FW_MEDIUM)
6011 TM.tmWeight = pOS2->usWeightClass;
6014 TM.tmDigitizedAspectX = 300;
6015 TM.tmDigitizedAspectY = 300;
6016 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6017 * symbol range to 0 - f0ff
6020 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6025 case 1257: /* Baltic */
6026 TM.tmLastChar = 0xf8fd;
6029 TM.tmLastChar = 0xf0ff;
6031 TM.tmBreakChar = 0x20;
6032 TM.tmDefaultChar = 0x1f;
6036 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6037 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6039 if(pOS2->usFirstCharIndex <= 1)
6040 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6041 else if (pOS2->usFirstCharIndex > 0xff)
6042 TM.tmBreakChar = 0x20;
6044 TM.tmBreakChar = pOS2->usFirstCharIndex;
6045 TM.tmDefaultChar = TM.tmBreakChar - 1;
6047 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6048 TM.tmUnderlined = font->underline;
6049 TM.tmStruckOut = font->strikeout;
6051 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6052 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6053 (pOS2->version == 0xFFFFU ||
6054 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6055 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6057 TM.tmPitchAndFamily = 0;
6059 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6061 case PAN_FAMILY_SCRIPT:
6062 TM.tmPitchAndFamily |= FF_SCRIPT;
6065 case PAN_FAMILY_DECORATIVE:
6066 TM.tmPitchAndFamily |= FF_DECORATIVE;
6071 case PAN_FAMILY_TEXT_DISPLAY:
6072 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6073 /* which is clearly not what the panose spec says. */
6075 if(TM.tmPitchAndFamily == 0 || /* fixed */
6076 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6077 TM.tmPitchAndFamily = FF_MODERN;
6080 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6085 TM.tmPitchAndFamily |= FF_DONTCARE;
6088 case PAN_SERIF_COVE:
6089 case PAN_SERIF_OBTUSE_COVE:
6090 case PAN_SERIF_SQUARE_COVE:
6091 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6092 case PAN_SERIF_SQUARE:
6093 case PAN_SERIF_THIN:
6094 case PAN_SERIF_BONE:
6095 case PAN_SERIF_EXAGGERATED:
6096 case PAN_SERIF_TRIANGLE:
6097 TM.tmPitchAndFamily |= FF_ROMAN;
6100 case PAN_SERIF_NORMAL_SANS:
6101 case PAN_SERIF_OBTUSE_SANS:
6102 case PAN_SERIF_PERP_SANS:
6103 case PAN_SERIF_FLARED:
6104 case PAN_SERIF_ROUNDED:
6105 TM.tmPitchAndFamily |= FF_SWISS;
6112 if(FT_IS_SCALABLE(ft_face))
6113 TM.tmPitchAndFamily |= TMPF_VECTOR;
6115 if(FT_IS_SFNT(ft_face))
6117 if (font->ntmFlags & NTM_PS_OPENTYPE)
6118 TM.tmPitchAndFamily |= TMPF_DEVICE;
6120 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6123 TM.tmCharSet = font->charset;
6125 font->potm->otmFiller = 0;
6126 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6127 font->potm->otmfsSelection = pOS2->fsSelection;
6128 font->potm->otmfsType = pOS2->fsType;
6129 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6130 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6131 font->potm->otmItalicAngle = 0; /* POST table */
6132 font->potm->otmEMSquare = ft_face->units_per_EM;
6133 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6134 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6135 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6136 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6137 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6138 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6139 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6140 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6141 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6142 font->potm->otmMacAscent = TM.tmAscent;
6143 font->potm->otmMacDescent = -TM.tmDescent;
6144 font->potm->otmMacLineGap = font->potm->otmLineGap;
6145 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6146 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6147 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6148 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6149 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6150 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6151 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6152 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6153 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6154 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6155 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6157 font->potm->otmsUnderscoreSize = 0;
6158 font->potm->otmsUnderscorePosition = 0;
6160 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6161 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6165 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6166 cp = (char*)font->potm + sizeof(*font->potm);
6167 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6168 strcpyW((WCHAR*)cp, family_nameW);
6170 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6171 strcpyW((WCHAR*)cp, style_nameW);
6173 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6174 strcpyW((WCHAR*)cp, family_nameW);
6175 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6176 strcatW((WCHAR*)cp, spaceW);
6177 strcatW((WCHAR*)cp, style_nameW);
6178 cp += lenfam + lensty;
6181 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6182 strcpyW((WCHAR*)cp, family_nameW);
6183 strcatW((WCHAR*)cp, spaceW);
6184 strcatW((WCHAR*)cp, style_nameW);
6188 HeapFree(GetProcessHeap(), 0, style_nameW);
6189 HeapFree(GetProcessHeap(), 0, family_nameW);
6193 /*************************************************************
6194 * WineEngGetGlyphOutline
6197 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6198 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6204 EnterCriticalSection( &freetype_cs );
6205 ret = get_glyph_outline( font, glyph, format, lpgm, buflen, buf, lpmat );
6206 LeaveCriticalSection( &freetype_cs );
6210 /*************************************************************
6211 * freetype_GetTextMetrics
6213 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6215 struct freetype_physdev *physdev = get_freetype_dev( dev );
6220 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6221 return dev->funcs->pGetTextMetrics( dev, metrics );
6225 EnterCriticalSection( &freetype_cs );
6226 ret = get_text_metrics( physdev->font, metrics );
6227 LeaveCriticalSection( &freetype_cs );
6231 /*************************************************************
6232 * WineEngGetOutlineTextMetrics
6235 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6236 OUTLINETEXTMETRICW *potm)
6240 TRACE("font=%p\n", font);
6242 if (!FT_IS_SCALABLE( font->ft_face )) return 0;
6245 EnterCriticalSection( &freetype_cs );
6247 if (font->potm || get_outline_text_metrics( font ))
6249 if(cbSize >= font->potm->otmSize)
6251 memcpy(potm, font->potm, font->potm->otmSize);
6252 scale_outline_font_metrics(font, potm);
6254 ret = font->potm->otmSize;
6256 LeaveCriticalSection( &freetype_cs );
6260 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6262 HFONTLIST *hfontlist;
6263 child->font = alloc_font();
6264 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6265 if(!child->font->ft_face)
6267 free_font(child->font);
6272 child->font->font_desc = font->font_desc;
6273 child->font->ntmFlags = child->face->ntmFlags;
6274 child->font->orientation = font->orientation;
6275 child->font->scale_y = font->scale_y;
6276 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6277 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6278 child->font->name = strdupW(child->face->family->FamilyName);
6279 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6280 child->font->base_font = font;
6281 list_add_head(&child_font_list, &child->font->entry);
6282 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6286 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6289 CHILD_FONT *child_font;
6292 font = font->base_font;
6294 *linked_font = font;
6296 if((*glyph = get_glyph_index(font, c)))
6299 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6301 if(!child_font->font)
6302 if(!load_child_font(font, child_font))
6305 if(!child_font->font->ft_face)
6307 g = get_glyph_index(child_font->font, c);
6311 *linked_font = child_font->font;
6318 /*************************************************************
6319 * freetype_GetCharWidth
6321 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6323 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6326 FT_UInt glyph_index;
6327 GdiFont *linked_font;
6328 struct freetype_physdev *physdev = get_freetype_dev( dev );
6332 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6333 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6336 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6339 EnterCriticalSection( &freetype_cs );
6340 for(c = firstChar; c <= lastChar; c++) {
6341 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6342 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6343 &gm, 0, NULL, &identity);
6344 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6346 LeaveCriticalSection( &freetype_cs );
6350 /*************************************************************
6351 * WineEngGetCharABCWidths
6354 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6357 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6360 FT_UInt glyph_index;
6361 GdiFont *linked_font;
6363 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6365 if(!FT_IS_SCALABLE(font->ft_face))
6369 EnterCriticalSection( &freetype_cs );
6371 for(c = firstChar; c <= lastChar; c++) {
6372 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6373 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6374 &gm, 0, NULL, &identity);
6375 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6376 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6377 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6378 FONT_GM(linked_font,glyph_index)->bbx;
6380 LeaveCriticalSection( &freetype_cs );
6384 /*************************************************************
6385 * WineEngGetCharABCWidthsFloat
6388 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6390 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6393 FT_UInt glyph_index;
6394 GdiFont *linked_font;
6396 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6399 EnterCriticalSection( &freetype_cs );
6401 for (c = first; c <= last; c++)
6403 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6404 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6405 &gm, 0, NULL, &identity);
6406 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6407 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6408 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6409 FONT_GM(linked_font, glyph_index)->lsb -
6410 FONT_GM(linked_font, glyph_index)->bbx;
6412 LeaveCriticalSection( &freetype_cs );
6416 /*************************************************************
6417 * WineEngGetCharABCWidthsI
6420 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6423 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6426 FT_UInt glyph_index;
6427 GdiFont *linked_font;
6429 if(!FT_HAS_HORIZONTAL(font->ft_face))
6433 EnterCriticalSection( &freetype_cs );
6435 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6437 for(c = firstChar; c < firstChar+count; c++) {
6438 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6439 &gm, 0, NULL, &identity);
6440 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6441 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6442 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6443 - FONT_GM(linked_font,c)->bbx;
6446 for(c = 0; c < count; c++) {
6447 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6448 &gm, 0, NULL, &identity);
6449 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6450 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6451 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6452 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6455 LeaveCriticalSection( &freetype_cs );
6459 /*************************************************************
6460 * freetype_GetTextExtentExPoint
6462 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6463 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6465 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6470 FT_UInt glyph_index;
6471 GdiFont *linked_font;
6472 struct freetype_physdev *physdev = get_freetype_dev( dev );
6476 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6477 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6480 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6483 EnterCriticalSection( &freetype_cs );
6486 get_text_metrics( physdev->font, &tm );
6487 size->cy = tm.tmHeight;
6489 for(idx = 0; idx < count; idx++) {
6490 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6491 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6492 &gm, 0, NULL, &identity);
6493 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6495 if (! pnfit || ext <= max_ext) {
6505 LeaveCriticalSection( &freetype_cs );
6506 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6510 /*************************************************************
6511 * WineEngGetTextExtentExPointI
6514 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6515 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6517 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6523 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6526 EnterCriticalSection( &freetype_cs );
6529 get_text_metrics(font, &tm);
6530 size->cy = tm.tmHeight;
6532 for(idx = 0; idx < count; idx++) {
6533 get_glyph_outline(font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6534 size->cx += FONT_GM(font,indices[idx])->adv;
6536 if (! pnfit || ext <= max_ext) {
6546 LeaveCriticalSection( &freetype_cs );
6547 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6551 /*************************************************************
6552 * WineEngGetFontData
6555 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6558 FT_Face ft_face = font->ft_face;
6562 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6563 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6564 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6566 if(!FT_IS_SFNT(ft_face))
6574 if(table) { /* MS tags differ in endianness from FT ones */
6575 table = table >> 24 | table << 24 |
6576 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6579 /* make sure value of len is the value freetype says it needs */
6582 FT_ULong needed = 0;
6583 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
6584 if( !err && needed < len) len = needed;
6586 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
6589 TRACE("Can't find table %c%c%c%c\n",
6590 /* bytes were reversed */
6591 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6592 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6598 /*************************************************************
6599 * WineEngGetTextFace
6602 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6604 INT n = strlenW(font->name) + 1;
6606 lstrcpynW(str, font->name, count);
6607 return min(count, n);
6612 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6614 if (fs) *fs = font->fs;
6615 return font->charset;
6618 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6620 GdiFont *font = dc->gdiFont, *linked_font;
6621 struct list *first_hfont;
6625 EnterCriticalSection( &freetype_cs );
6626 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6627 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6628 if(font == linked_font)
6629 *new_hfont = dc->hFont;
6632 first_hfont = list_head(&linked_font->hfontlist);
6633 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6635 LeaveCriticalSection( &freetype_cs );
6639 /* Retrieve a list of supported Unicode ranges for a given font.
6640 * Can be called with NULL gs to calculate the buffer size. Returns
6641 * the number of ranges found.
6643 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6645 DWORD num_ranges = 0;
6647 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6650 FT_ULong char_code, char_code_prev;
6653 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6655 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6656 face->num_glyphs, glyph_code, char_code);
6658 if (!glyph_code) return 0;
6662 gs->ranges[0].wcLow = (USHORT)char_code;
6663 gs->ranges[0].cGlyphs = 0;
6664 gs->cGlyphsSupported = 0;
6670 if (char_code < char_code_prev)
6672 ERR("expected increasing char code from FT_Get_Next_Char\n");
6675 if (char_code - char_code_prev > 1)
6680 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6681 gs->ranges[num_ranges - 1].cGlyphs = 1;
6682 gs->cGlyphsSupported++;
6687 gs->ranges[num_ranges - 1].cGlyphs++;
6688 gs->cGlyphsSupported++;
6690 char_code_prev = char_code;
6691 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6695 FIXME("encoding %u not supported\n", face->charmap->encoding);
6700 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6703 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6705 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6708 glyphset->cbThis = size;
6709 glyphset->cRanges = num_ranges;
6710 glyphset->flAccel = 0;
6715 /*************************************************************
6718 BOOL WineEngFontIsLinked(GdiFont *font)
6722 EnterCriticalSection( &freetype_cs );
6723 ret = !list_empty(&font->child_fonts);
6724 LeaveCriticalSection( &freetype_cs );
6728 static BOOL is_hinting_enabled(void)
6730 /* Use the >= 2.2.0 function if available */
6731 if(pFT_Get_TrueType_Engine_Type)
6733 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6734 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6736 #ifdef FT_DRIVER_HAS_HINTER
6741 /* otherwise if we've been compiled with < 2.2.0 headers
6742 use the internal macro */
6743 mod = pFT_Get_Module(library, "truetype");
6744 if(mod && FT_DRIVER_HAS_HINTER(mod))
6752 static BOOL is_subpixel_rendering_enabled( void )
6754 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6755 return pFT_Library_SetLcdFilter &&
6756 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6762 /*************************************************************************
6763 * GetRasterizerCaps (GDI32.@)
6765 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6767 static int hinting = -1;
6768 static int subpixel = -1;
6772 hinting = is_hinting_enabled();
6773 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6776 if ( subpixel == -1 )
6778 subpixel = is_subpixel_rendering_enabled();
6779 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6782 lprs->nSize = sizeof(RASTERIZER_STATUS);
6783 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6785 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6786 lprs->nLanguageID = 0;
6790 /*************************************************************
6791 * WineEngRealizationInfo
6793 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6795 FIXME("(%p, %p): stub!\n", font, info);
6798 if(FT_IS_SCALABLE(font->ft_face))
6801 info->cache_num = font->cache_num;
6802 info->unknown2 = -1;
6806 /*************************************************************************
6807 * Kerning support for TrueType fonts
6809 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6811 struct TT_kern_table
6817 struct TT_kern_subtable
6826 USHORT horizontal : 1;
6828 USHORT cross_stream: 1;
6829 USHORT override : 1;
6830 USHORT reserved1 : 4;
6836 struct TT_format0_kern_subtable
6840 USHORT entrySelector;
6851 static DWORD parse_format0_kern_subtable(GdiFont *font,
6852 const struct TT_format0_kern_subtable *tt_f0_ks,
6853 const USHORT *glyph_to_char,
6854 KERNINGPAIR *kern_pair, DWORD cPairs)
6857 const struct TT_kern_pair *tt_kern_pair;
6859 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6861 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6863 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6864 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6865 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6867 if (!kern_pair || !cPairs)
6870 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6872 nPairs = min(nPairs, cPairs);
6874 for (i = 0; i < nPairs; i++)
6876 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6877 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6878 /* this algorithm appears to better match what Windows does */
6879 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6880 if (kern_pair->iKernAmount < 0)
6882 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6883 kern_pair->iKernAmount -= font->ppem;
6885 else if (kern_pair->iKernAmount > 0)
6887 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6888 kern_pair->iKernAmount += font->ppem;
6890 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6892 TRACE("left %u right %u value %d\n",
6893 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6897 TRACE("copied %u entries\n", nPairs);
6901 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6905 const struct TT_kern_table *tt_kern_table;
6906 const struct TT_kern_subtable *tt_kern_subtable;
6908 USHORT *glyph_to_char;
6911 EnterCriticalSection( &freetype_cs );
6912 if (font->total_kern_pairs != (DWORD)-1)
6914 if (cPairs && kern_pair)
6916 cPairs = min(cPairs, font->total_kern_pairs);
6917 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6918 LeaveCriticalSection( &freetype_cs );
6921 LeaveCriticalSection( &freetype_cs );
6922 return font->total_kern_pairs;
6925 font->total_kern_pairs = 0;
6927 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6929 if (length == GDI_ERROR)
6931 TRACE("no kerning data in the font\n");
6932 LeaveCriticalSection( &freetype_cs );
6936 buf = HeapAlloc(GetProcessHeap(), 0, length);
6939 WARN("Out of memory\n");
6940 LeaveCriticalSection( &freetype_cs );
6944 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6946 /* build a glyph index to char code map */
6947 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6950 WARN("Out of memory allocating a glyph index to char code map\n");
6951 HeapFree(GetProcessHeap(), 0, buf);
6952 LeaveCriticalSection( &freetype_cs );
6956 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
6962 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6964 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6965 font->ft_face->num_glyphs, glyph_code, char_code);
6969 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6971 /* FIXME: This doesn't match what Windows does: it does some fancy
6972 * things with duplicate glyph index to char code mappings, while
6973 * we just avoid overriding existing entries.
6975 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6976 glyph_to_char[glyph_code] = (USHORT)char_code;
6978 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6985 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6986 for (n = 0; n <= 65535; n++)
6987 glyph_to_char[n] = (USHORT)n;
6990 tt_kern_table = buf;
6991 nTables = GET_BE_WORD(tt_kern_table->nTables);
6992 TRACE("version %u, nTables %u\n",
6993 GET_BE_WORD(tt_kern_table->version), nTables);
6995 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6997 for (i = 0; i < nTables; i++)
6999 struct TT_kern_subtable tt_kern_subtable_copy;
7001 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7002 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7003 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7005 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7006 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7007 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7009 /* According to the TrueType specification this is the only format
7010 * that will be properly interpreted by Windows and OS/2
7012 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7014 DWORD new_chunk, old_total = font->total_kern_pairs;
7016 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7017 glyph_to_char, NULL, 0);
7018 font->total_kern_pairs += new_chunk;
7020 if (!font->kern_pairs)
7021 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7022 font->total_kern_pairs * sizeof(*font->kern_pairs));
7024 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7025 font->total_kern_pairs * sizeof(*font->kern_pairs));
7027 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7028 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7031 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7033 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7036 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7037 HeapFree(GetProcessHeap(), 0, buf);
7039 if (cPairs && kern_pair)
7041 cPairs = min(cPairs, font->total_kern_pairs);
7042 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7043 LeaveCriticalSection( &freetype_cs );
7046 LeaveCriticalSection( &freetype_cs );
7047 return font->total_kern_pairs;
7050 static const struct gdi_dc_funcs freetype_funcs =
7052 NULL, /* pAbortDoc */
7053 NULL, /* pAbortPath */
7054 NULL, /* pAlphaBlend */
7055 NULL, /* pAngleArc */
7058 NULL, /* pBeginPath */
7059 NULL, /* pBlendImage */
7060 NULL, /* pChoosePixelFormat */
7062 NULL, /* pCloseFigure */
7063 NULL, /* pCreateBitmap */
7064 NULL, /* pCreateCompatibleDC */
7065 freetype_CreateDC, /* pCreateDC */
7066 NULL, /* pCreateDIBSection */
7067 NULL, /* pDeleteBitmap */
7068 freetype_DeleteDC, /* pDeleteDC */
7069 NULL, /* pDeleteObject */
7070 NULL, /* pDescribePixelFormat */
7071 NULL, /* pDeviceCapabilities */
7072 NULL, /* pEllipse */
7074 NULL, /* pEndPage */
7075 NULL, /* pEndPath */
7076 freetype_EnumFonts, /* pEnumFonts */
7077 NULL, /* pEnumICMProfiles */
7078 NULL, /* pExcludeClipRect */
7079 NULL, /* pExtDeviceMode */
7080 NULL, /* pExtEscape */
7081 NULL, /* pExtFloodFill */
7082 NULL, /* pExtSelectClipRgn */
7083 NULL, /* pExtTextOut */
7084 NULL, /* pFillPath */
7085 NULL, /* pFillRgn */
7086 NULL, /* pFlattenPath */
7087 NULL, /* pFontIsLinked */
7088 NULL, /* pFrameRgn */
7089 NULL, /* pGdiComment */
7090 NULL, /* pGdiRealizationInfo */
7091 NULL, /* pGetCharABCWidths */
7092 NULL, /* pGetCharABCWidthsI */
7093 freetype_GetCharWidth, /* pGetCharWidth */
7094 NULL, /* pGetDeviceCaps */
7095 NULL, /* pGetDeviceGammaRamp */
7096 NULL, /* pGetFontData */
7097 NULL, /* pGetFontUnicodeRanges */
7098 NULL, /* pGetGlyphIndices */
7099 NULL, /* pGetGlyphOutline */
7100 NULL, /* pGetICMProfile */
7101 NULL, /* pGetImage */
7102 NULL, /* pGetKerningPairs */
7103 NULL, /* pGetNearestColor */
7104 NULL, /* pGetOutlineTextMetrics */
7105 NULL, /* pGetPixel */
7106 NULL, /* pGetPixelFormat */
7107 NULL, /* pGetSystemPaletteEntries */
7108 NULL, /* pGetTextCharsetInfo */
7109 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7110 NULL, /* pGetTextExtentExPointI */
7111 NULL, /* pGetTextFace */
7112 freetype_GetTextMetrics, /* pGetTextMetrics */
7113 NULL, /* pIntersectClipRect */
7114 NULL, /* pInvertRgn */
7116 NULL, /* pModifyWorldTransform */
7118 NULL, /* pOffsetClipRgn */
7119 NULL, /* pOffsetViewportOrg */
7120 NULL, /* pOffsetWindowOrg */
7121 NULL, /* pPaintRgn */
7124 NULL, /* pPolyBezier */
7125 NULL, /* pPolyBezierTo */
7126 NULL, /* pPolyDraw */
7127 NULL, /* pPolyPolygon */
7128 NULL, /* pPolyPolyline */
7129 NULL, /* pPolygon */
7130 NULL, /* pPolyline */
7131 NULL, /* pPolylineTo */
7132 NULL, /* pPutImage */
7133 NULL, /* pRealizeDefaultPalette */
7134 NULL, /* pRealizePalette */
7135 NULL, /* pRectangle */
7136 NULL, /* pResetDC */
7137 NULL, /* pRestoreDC */
7138 NULL, /* pRoundRect */
7140 NULL, /* pScaleViewportExt */
7141 NULL, /* pScaleWindowExt */
7142 NULL, /* pSelectBitmap */
7143 NULL, /* pSelectBrush */
7144 NULL, /* pSelectClipPath */
7145 freetype_SelectFont, /* pSelectFont */
7146 NULL, /* pSelectPalette */
7147 NULL, /* pSelectPen */
7148 NULL, /* pSetArcDirection */
7149 NULL, /* pSetBkColor */
7150 NULL, /* pSetBkMode */
7151 NULL, /* pSetDCBrushColor */
7152 NULL, /* pSetDCPenColor */
7153 NULL, /* pSetDIBColorTable */
7154 NULL, /* pSetDIBitsToDevice */
7155 NULL, /* pSetDeviceClipping */
7156 NULL, /* pSetDeviceGammaRamp */
7157 NULL, /* pSetLayout */
7158 NULL, /* pSetMapMode */
7159 NULL, /* pSetMapperFlags */
7160 NULL, /* pSetPixel */
7161 NULL, /* pSetPixelFormat */
7162 NULL, /* pSetPolyFillMode */
7163 NULL, /* pSetROP2 */
7164 NULL, /* pSetRelAbs */
7165 NULL, /* pSetStretchBltMode */
7166 NULL, /* pSetTextAlign */
7167 NULL, /* pSetTextCharacterExtra */
7168 NULL, /* pSetTextColor */
7169 NULL, /* pSetTextJustification */
7170 NULL, /* pSetViewportExt */
7171 NULL, /* pSetViewportOrg */
7172 NULL, /* pSetWindowExt */
7173 NULL, /* pSetWindowOrg */
7174 NULL, /* pSetWorldTransform */
7175 NULL, /* pStartDoc */
7176 NULL, /* pStartPage */
7177 NULL, /* pStretchBlt */
7178 NULL, /* pStretchDIBits */
7179 NULL, /* pStrokeAndFillPath */
7180 NULL, /* pStrokePath */
7181 NULL, /* pSwapBuffers */
7182 NULL, /* pUnrealizePalette */
7183 NULL, /* pWidenPath */
7184 /* OpenGL not supported */
7187 #else /* HAVE_FREETYPE */
7189 /*************************************************************************/
7191 BOOL WineEngInit(void)
7195 BOOL WineEngDestroyFontInstance(HFONT hfont)
7200 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
7201 LPWORD pgi, DWORD flags)
7206 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
7207 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
7210 ERR("called but we don't have FreeType\n");
7214 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
7215 OUTLINETEXTMETRICW *potm)
7217 ERR("called but we don't have FreeType\n");
7221 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
7224 ERR("called but we don't have FreeType\n");
7228 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
7230 ERR("called but we don't have FreeType\n");
7234 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
7237 ERR("called but we don't have FreeType\n");
7241 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
7242 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
7244 ERR("called but we don't have FreeType\n");
7248 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
7251 ERR("called but we don't have FreeType\n");
7255 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
7257 ERR("called but we don't have FreeType\n");
7261 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7263 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7267 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7269 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7273 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7275 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7279 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
7281 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
7282 return DEFAULT_CHARSET;
7285 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7290 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
7292 FIXME("(%p, %p): stub\n", font, glyphset);
7296 BOOL WineEngFontIsLinked(GdiFont *font)
7301 /*************************************************************************
7302 * GetRasterizerCaps (GDI32.@)
7304 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7306 lprs->nSize = sizeof(RASTERIZER_STATUS);
7308 lprs->nLanguageID = 0;
7312 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
7314 ERR("called but we don't have FreeType\n");
7318 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
7320 ERR("called but we don't have FreeType\n");
7324 #endif /* HAVE_FREETYPE */