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) );
3119 LPSTR next = strchr( ptr, ':' );
3120 if (next) *next++ = 0;
3121 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3122 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3124 strcpy( unixname, home );
3125 strcat( unixname, ptr + 1 );
3126 ReadFontDir( unixname, TRUE );
3127 HeapFree( GetProcessHeap(), 0, unixname );
3130 ReadFontDir( ptr, TRUE );
3133 HeapFree( GetProcessHeap(), 0, valueA );
3135 HeapFree( GetProcessHeap(), 0, valueW );
3141 static BOOL move_to_front(const WCHAR *name)
3143 Family *family, *cursor2;
3144 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3146 if(!strcmpiW(family->FamilyName, name))
3148 list_remove(&family->entry);
3149 list_add_head(&font_list, &family->entry);
3156 static BOOL set_default(const WCHAR **name_list)
3160 if (move_to_front(*name_list)) return TRUE;
3167 static void reorder_font_list(void)
3169 set_default( default_serif_list );
3170 set_default( default_fixed_list );
3171 set_default( default_sans_list );
3174 /*************************************************************
3177 * Initialize FreeType library and create a list of available faces
3179 BOOL WineEngInit(void)
3181 HKEY hkey_font_cache;
3185 /* update locale dependent font info in registry */
3188 if(!init_freetype()) return FALSE;
3190 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3192 ERR("Failed to create font mutex\n");
3195 WaitForSingleObject(font_mutex, INFINITE);
3197 create_font_cache_key(&hkey_font_cache, &disposition);
3199 if(disposition == REG_CREATED_NEW_KEY)
3202 load_font_list_from_cache(hkey_font_cache);
3204 RegCloseKey(hkey_font_cache);
3206 reorder_font_list();
3213 if(disposition == REG_CREATED_NEW_KEY)
3214 update_reg_entries();
3216 update_system_links();
3217 init_system_links();
3219 ReleaseMutex(font_mutex);
3224 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3227 TT_HoriHeader *pHori;
3231 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3232 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3234 if(height == 0) height = 16;
3236 /* Calc. height of EM square:
3238 * For +ve lfHeight we have
3239 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3240 * Re-arranging gives:
3241 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3243 * For -ve lfHeight we have
3245 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3246 * with il = winAscent + winDescent - units_per_em]
3251 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3252 ppem = MulDiv(ft_face->units_per_EM, height,
3253 pHori->Ascender - pHori->Descender);
3255 ppem = MulDiv(ft_face->units_per_EM, height,
3256 pOS2->usWinAscent + pOS2->usWinDescent);
3264 static struct font_mapping *map_font_file( const char *name )
3266 struct font_mapping *mapping;
3270 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3271 if (fstat( fd, &st ) == -1) goto error;
3273 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3275 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3277 mapping->refcount++;
3282 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3285 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3288 if (mapping->data == MAP_FAILED)
3290 HeapFree( GetProcessHeap(), 0, mapping );
3293 mapping->refcount = 1;
3294 mapping->dev = st.st_dev;
3295 mapping->ino = st.st_ino;
3296 mapping->size = st.st_size;
3297 list_add_tail( &mappings_list, &mapping->entry );
3305 static void unmap_font_file( struct font_mapping *mapping )
3307 if (!--mapping->refcount)
3309 list_remove( &mapping->entry );
3310 munmap( mapping->data, mapping->size );
3311 HeapFree( GetProcessHeap(), 0, mapping );
3315 static LONG load_VDMX(GdiFont*, LONG);
3317 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3324 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3328 if (!(font->mapping = map_font_file( face->file )))
3330 WARN("failed to map %s\n", debugstr_a(face->file));
3333 data_ptr = font->mapping->data;
3334 data_size = font->mapping->size;
3338 data_ptr = face->font_data_ptr;
3339 data_size = face->font_data_size;
3342 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3344 ERR("FT_New_Face rets %d\n", err);
3348 /* set it here, as load_VDMX needs it */
3349 font->ft_face = ft_face;
3351 if(FT_IS_SCALABLE(ft_face)) {
3352 /* load the VDMX table if we have one */
3353 font->ppem = load_VDMX(font, height);
3355 font->ppem = calc_ppem_for_height(ft_face, height);
3356 TRACE("height %d => ppem %d\n", height, font->ppem);
3358 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3359 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3361 font->ppem = height;
3362 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3363 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3369 static int get_nearest_charset(Face *face, int *cp)
3371 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3372 a single face with the requested charset. The idea is to check if
3373 the selected font supports the current ANSI codepage, if it does
3374 return the corresponding charset, else return the first charset */
3377 int acp = GetACP(), i;
3381 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3382 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3383 return csi.ciCharset;
3385 for(i = 0; i < 32; i++) {
3387 if(face->fs.fsCsb[0] & fs0) {
3388 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3390 return csi.ciCharset;
3393 FIXME("TCI failing on %x\n", fs0);
3397 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3398 face->fs.fsCsb[0], face->file);
3400 return DEFAULT_CHARSET;
3403 static GdiFont *alloc_font(void)
3405 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3407 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3408 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3410 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3411 ret->total_kern_pairs = (DWORD)-1;
3412 ret->kern_pairs = NULL;
3413 list_init(&ret->hfontlist);
3414 list_init(&ret->child_fonts);
3418 static void free_font(GdiFont *font)
3420 struct list *cursor, *cursor2;
3423 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3425 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3426 list_remove(cursor);
3428 free_font(child->font);
3429 HeapFree(GetProcessHeap(), 0, child);
3432 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3434 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3435 DeleteObject(hfontlist->hfont);
3436 list_remove(&hfontlist->entry);
3437 HeapFree(GetProcessHeap(), 0, hfontlist);
3440 if (font->ft_face) pFT_Done_Face(font->ft_face);
3441 if (font->mapping) unmap_font_file( font->mapping );
3442 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3443 HeapFree(GetProcessHeap(), 0, font->potm);
3444 HeapFree(GetProcessHeap(), 0, font->name);
3445 for (i = 0; i < font->gmsize; i++)
3446 HeapFree(GetProcessHeap(),0,font->gm[i]);
3447 HeapFree(GetProcessHeap(), 0, font->gm);
3448 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3449 HeapFree(GetProcessHeap(), 0, font);
3453 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3455 FT_Face ft_face = font->ft_face;
3459 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3466 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3468 /* make sure value of len is the value freetype says it needs */
3471 FT_ULong needed = 0;
3472 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3473 if( !err && needed < len) len = needed;
3475 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3478 TRACE("Can't find table %c%c%c%c\n",
3479 /* bytes were reversed */
3480 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3481 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3487 /*************************************************************
3490 * load the vdmx entry for the specified height
3493 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3494 ( ( (FT_ULong)_x4 << 24 ) | \
3495 ( (FT_ULong)_x3 << 16 ) | \
3496 ( (FT_ULong)_x2 << 8 ) | \
3499 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3514 static LONG load_VDMX(GdiFont *font, LONG height)
3518 BYTE devXRatio, devYRatio;
3519 USHORT numRecs, numRatios;
3520 DWORD result, offset = -1;
3524 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3526 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3529 /* FIXME: need the real device aspect ratio */
3533 numRecs = GET_BE_WORD(hdr[1]);
3534 numRatios = GET_BE_WORD(hdr[2]);
3536 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3537 for(i = 0; i < numRatios; i++) {
3540 offset = (3 * 2) + (i * sizeof(Ratios));
3541 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3544 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3546 if((ratio.xRatio == 0 &&
3547 ratio.yStartRatio == 0 &&
3548 ratio.yEndRatio == 0) ||
3549 (devXRatio == ratio.xRatio &&
3550 devYRatio >= ratio.yStartRatio &&
3551 devYRatio <= ratio.yEndRatio))
3553 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3554 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3555 offset = GET_BE_WORD(tmp);
3561 FIXME("No suitable ratio found\n");
3565 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3567 BYTE startsz, endsz;
3570 recs = GET_BE_WORD(group.recs);
3571 startsz = group.startsz;
3572 endsz = group.endsz;
3574 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3576 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3577 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3578 if(result == GDI_ERROR) {
3579 FIXME("Failed to retrieve vTable\n");
3584 for(i = 0; i < recs; i++) {
3585 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3586 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3587 ppem = GET_BE_WORD(vTable[i * 3]);
3589 if(yMax + -yMin == height) {
3592 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3595 if(yMax + -yMin > height) {
3598 goto end; /* failed */
3600 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3601 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3602 ppem = GET_BE_WORD(vTable[i * 3]);
3603 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3609 TRACE("ppem not found for height %d\n", height);
3613 HeapFree(GetProcessHeap(), 0, vTable);
3619 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3621 if(font->font_desc.hash != fd->hash) return TRUE;
3622 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3623 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3624 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3625 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3628 static void calc_hash(FONT_DESC *pfd)
3630 DWORD hash = 0, *ptr, two_chars;
3634 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3636 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3638 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3640 pwc = (WCHAR *)&two_chars;
3642 *pwc = toupperW(*pwc);
3644 *pwc = toupperW(*pwc);
3648 hash ^= !pfd->can_use_bitmap;
3653 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3658 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3662 fd.can_use_bitmap = can_use_bitmap;
3665 /* try the child list */
3666 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3667 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3668 if(!fontcmp(ret, &fd)) {
3669 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3670 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3671 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3672 if(hflist->hfont == hfont)
3678 /* try the in-use list */
3679 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3680 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3681 if(!fontcmp(ret, &fd)) {
3682 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3683 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3684 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3685 if(hflist->hfont == hfont)
3688 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3689 hflist->hfont = hfont;
3690 list_add_head(&ret->hfontlist, &hflist->entry);
3695 /* then the unused list */
3696 font_elem_ptr = list_head(&unused_gdi_font_list);
3697 while(font_elem_ptr) {
3698 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3699 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3700 if(!fontcmp(ret, &fd)) {
3701 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3702 assert(list_empty(&ret->hfontlist));
3703 TRACE("Found %p in unused list\n", ret);
3704 list_remove(&ret->entry);
3705 list_add_head(&gdi_font_list, &ret->entry);
3706 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3707 hflist->hfont = hfont;
3708 list_add_head(&ret->hfontlist, &hflist->entry);
3715 static void add_to_cache(GdiFont *font)
3717 static DWORD cache_num = 1;
3719 font->cache_num = cache_num++;
3720 list_add_head(&gdi_font_list, &font->entry);
3723 /*************************************************************
3724 * create_child_font_list
3726 static BOOL create_child_font_list(GdiFont *font)
3729 SYSTEM_LINKS *font_link;
3730 CHILD_FONT *font_link_entry, *new_child;
3734 psub = get_font_subst(&font_subst_list, font->name, -1);
3735 font_name = psub ? psub->to.name : font->name;
3736 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3738 if(!strcmpiW(font_link->font_name, font_name))
3740 TRACE("found entry in system list\n");
3741 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3743 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3744 new_child->face = font_link_entry->face;
3745 new_child->font = NULL;
3746 list_add_tail(&font->child_fonts, &new_child->entry);
3747 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3754 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3755 * Sans Serif. This is how asian windows get default fallbacks for fonts
3757 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3758 font->charset != OEM_CHARSET &&
3759 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3760 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3762 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3764 TRACE("found entry in default fallback list\n");
3765 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3767 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3768 new_child->face = font_link_entry->face;
3769 new_child->font = NULL;
3770 list_add_tail(&font->child_fonts, &new_child->entry);
3771 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3781 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3783 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3785 if (pFT_Set_Charmap)
3788 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3790 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3792 for (i = 0; i < ft_face->num_charmaps; i++)
3794 if (ft_face->charmaps[i]->encoding == encoding)
3796 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3797 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3799 switch (ft_face->charmaps[i]->platform_id)
3802 cmap_def = ft_face->charmaps[i];
3804 case 0: /* Apple Unicode */
3805 cmap0 = ft_face->charmaps[i];
3807 case 1: /* Macintosh */
3808 cmap1 = ft_face->charmaps[i];
3811 cmap2 = ft_face->charmaps[i];
3813 case 3: /* Microsoft */
3814 cmap3 = ft_face->charmaps[i];
3819 if (cmap3) /* prefer Microsoft cmap table */
3820 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3822 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3824 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3826 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3828 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3830 return ft_err == FT_Err_Ok;
3833 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3837 /*************************************************************
3840 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3841 LPCWSTR output, const DEVMODEW *devmode )
3843 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3845 if (!physdev) return FALSE;
3846 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3851 /*************************************************************
3854 static BOOL freetype_DeleteDC( PHYSDEV dev )
3856 struct freetype_physdev *physdev = get_freetype_dev( dev );
3857 HeapFree( GetProcessHeap(), 0, physdev );
3862 /*************************************************************
3863 * freetype_SelectFont
3865 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3867 struct freetype_physdev *physdev = get_freetype_dev( dev );
3869 Face *face, *best, *best_bitmap;
3870 Family *family, *last_resort_family;
3871 struct list *family_elem_ptr, *face_elem_ptr;
3872 INT height, width = 0;
3873 unsigned int score = 0, new_score;
3874 signed int diff = 0, newdiff;
3875 BOOL bd, it, can_use_bitmap;
3880 FontSubst *psub = NULL;
3881 DC *dc = get_dc_ptr( dev->hdc );
3883 if (!hfont) /* notification that the font has been changed by another driver */
3886 physdev->font = NULL;
3887 release_dc_ptr( dc );
3891 GetObjectW( hfont, sizeof(lf), &lf );
3892 lf.lfWidth = abs(lf.lfWidth);
3894 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3896 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3897 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3898 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3901 if(dc->GraphicsMode == GM_ADVANCED)
3902 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3905 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3906 font scaling abilities. */
3907 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3908 dcmat.eM21 = dcmat.eM12 = 0;
3911 /* Try to avoid not necessary glyph transformations */
3912 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3914 lf.lfHeight *= fabs(dcmat.eM11);
3915 lf.lfWidth *= fabs(dcmat.eM11);
3916 dcmat.eM11 = dcmat.eM22 = 1.0;
3919 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3920 dcmat.eM21, dcmat.eM22);
3923 EnterCriticalSection( &freetype_cs );
3925 /* check the cache first */
3926 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3927 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3931 if(list_empty(&font_list)) /* No fonts installed */
3933 TRACE("No fonts installed\n");
3937 TRACE("not in cache\n");
3940 ret->font_desc.matrix = dcmat;
3941 ret->font_desc.lf = lf;
3942 ret->font_desc.can_use_bitmap = can_use_bitmap;
3943 calc_hash(&ret->font_desc);
3944 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3945 hflist->hfont = hfont;
3946 list_add_head(&ret->hfontlist, &hflist->entry);
3948 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3949 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3950 original value lfCharSet. Note this is a special case for
3951 Symbol and doesn't happen at least for "Wingdings*" */
3953 if(!strcmpiW(lf.lfFaceName, SymbolW))
3954 lf.lfCharSet = SYMBOL_CHARSET;
3956 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3957 switch(lf.lfCharSet) {
3958 case DEFAULT_CHARSET:
3959 csi.fs.fsCsb[0] = 0;
3962 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3963 csi.fs.fsCsb[0] = 0;
3969 if(lf.lfFaceName[0] != '\0') {
3970 SYSTEM_LINKS *font_link;
3971 CHILD_FONT *font_link_entry;
3972 LPWSTR FaceName = lf.lfFaceName;
3975 * Check for a leading '@' this signals that the font is being
3976 * requested in tategaki mode (vertical writing substitution) but
3977 * does not affect the fontface that is to be selected.
3979 if (lf.lfFaceName[0]=='@')
3980 FaceName = &lf.lfFaceName[1];
3982 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3985 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3986 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3987 if (psub->to.charset != -1)
3988 lf.lfCharSet = psub->to.charset;
3991 /* We want a match on name and charset or just name if
3992 charset was DEFAULT_CHARSET. If the latter then
3993 we fixup the returned charset later in get_nearest_charset
3994 where we'll either use the charset of the current ansi codepage
3995 or if that's unavailable the first charset that the font supports.
3997 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3998 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3999 if (!strcmpiW(family->FamilyName, FaceName) ||
4000 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4002 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4003 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4004 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4005 if(face->scalable || can_use_bitmap)
4011 /* Search by full face name. */
4012 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4013 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4014 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4015 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4016 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4017 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
4019 if(face->scalable || can_use_bitmap)
4026 * Try check the SystemLink list first for a replacement font.
4027 * We may find good replacements there.
4029 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4031 if(!strcmpiW(font_link->font_name, FaceName) ||
4032 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4034 TRACE("found entry in system list\n");
4035 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4037 face = font_link_entry->face;
4038 family = face->family;
4039 if(csi.fs.fsCsb[0] &
4040 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4042 if(face->scalable || can_use_bitmap)
4050 psub = NULL; /* substitution is no more relevant */
4052 /* If requested charset was DEFAULT_CHARSET then try using charset
4053 corresponding to the current ansi codepage */
4054 if (!csi.fs.fsCsb[0])
4057 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4058 FIXME("TCI failed on codepage %d\n", acp);
4059 csi.fs.fsCsb[0] = 0;
4061 lf.lfCharSet = csi.ciCharset;
4064 /* Face families are in the top 4 bits of lfPitchAndFamily,
4065 so mask with 0xF0 before testing */
4067 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4068 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4069 strcpyW(lf.lfFaceName, defFixed);
4070 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4071 strcpyW(lf.lfFaceName, defSerif);
4072 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4073 strcpyW(lf.lfFaceName, defSans);
4075 strcpyW(lf.lfFaceName, defSans);
4076 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4077 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4078 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4079 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4080 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4081 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4082 if(face->scalable || can_use_bitmap)
4088 last_resort_family = NULL;
4089 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4090 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4091 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4092 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4093 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4096 if(can_use_bitmap && !last_resort_family)
4097 last_resort_family = family;
4102 if(last_resort_family) {
4103 family = last_resort_family;
4104 csi.fs.fsCsb[0] = 0;
4108 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4109 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4110 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4111 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4112 if(face->scalable) {
4113 csi.fs.fsCsb[0] = 0;
4114 WARN("just using first face for now\n");
4117 if(can_use_bitmap && !last_resort_family)
4118 last_resort_family = family;
4121 if(!last_resort_family) {
4122 FIXME("can't find a single appropriate font - bailing\n");
4128 WARN("could only find a bitmap font - this will probably look awful!\n");
4129 family = last_resort_family;
4130 csi.fs.fsCsb[0] = 0;
4133 it = lf.lfItalic ? 1 : 0;
4134 bd = lf.lfWeight > 550 ? 1 : 0;
4136 height = lf.lfHeight;
4138 face = best = best_bitmap = NULL;
4139 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4141 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4145 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4146 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4147 new_score = (italic ^ it) + (bold ^ bd);
4148 if(!best || new_score <= score)
4150 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4151 italic, bold, it, bd);
4154 if(best->scalable && score == 0) break;
4158 newdiff = height - (signed int)(best->size.height);
4160 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4161 if(!best_bitmap || new_score < score ||
4162 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4164 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4167 if(score == 0 && diff == 0) break;
4174 face = best->scalable ? best : best_bitmap;
4175 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4176 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4179 height = lf.lfHeight;
4183 if(csi.fs.fsCsb[0]) {
4184 ret->charset = lf.lfCharSet;
4185 ret->codepage = csi.ciACP;
4188 ret->charset = get_nearest_charset(face, &ret->codepage);
4190 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4191 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4193 ret->aveWidth = height ? lf.lfWidth : 0;
4195 if(!face->scalable) {
4196 /* Windows uses integer scaling factors for bitmap fonts */
4197 INT scale, scaled_height;
4198 GdiFont *cachedfont;
4200 /* FIXME: rotation of bitmap fonts is ignored */
4201 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4203 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4204 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4205 dcmat.eM11 = dcmat.eM22 = 1.0;
4206 /* As we changed the matrix, we need to search the cache for the font again,
4207 * otherwise we might explode the cache. */
4208 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4209 TRACE("Found cached font after non-scalable matrix rescale!\n");
4214 calc_hash(&ret->font_desc);
4216 if (height != 0) height = diff;
4217 height += face->size.height;
4219 scale = (height + face->size.height - 1) / face->size.height;
4220 scaled_height = scale * face->size.height;
4221 /* Only jump to the next height if the difference <= 25% original height */
4222 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4223 /* The jump between unscaled and doubled is delayed by 1 */
4224 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4225 ret->scale_y = scale;
4227 width = face->size.x_ppem >> 6;
4228 height = face->size.y_ppem >> 6;
4232 TRACE("font scale y: %f\n", ret->scale_y);
4234 ret->ft_face = OpenFontFace(ret, face, width, height);
4243 ret->ntmFlags = face->ntmFlags;
4245 if (ret->charset == SYMBOL_CHARSET &&
4246 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4249 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4253 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4256 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4257 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4258 ret->underline = lf.lfUnderline ? 0xff : 0;
4259 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4260 create_child_font_list(ret);
4262 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
4264 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4265 if (length != GDI_ERROR)
4267 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4268 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4269 TRACE("Loaded GSUB table of %i bytes\n",length);
4273 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4280 physdev->font = ret;
4282 LeaveCriticalSection( &freetype_cs );
4283 release_dc_ptr( dc );
4284 return ret ? hfont : 0;
4287 static void dump_gdi_font_list(void)
4290 struct list *elem_ptr;
4292 TRACE("---------- gdiFont Cache ----------\n");
4293 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4294 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4295 TRACE("gdiFont=%p %s %d\n",
4296 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4299 TRACE("---------- Unused gdiFont Cache ----------\n");
4300 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4301 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4302 TRACE("gdiFont=%p %s %d\n",
4303 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4306 TRACE("---------- Child gdiFont Cache ----------\n");
4307 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4308 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4309 TRACE("gdiFont=%p %s %d\n",
4310 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4314 /*************************************************************
4315 * WineEngDestroyFontInstance
4317 * free the gdiFont associated with this handle
4320 BOOL WineEngDestroyFontInstance(HFONT handle)
4325 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4329 EnterCriticalSection( &freetype_cs );
4331 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4333 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4334 while(hfontlist_elem_ptr) {
4335 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4336 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4337 if(hflist->hfont == handle) {
4338 TRACE("removing child font %p from child list\n", gdiFont);
4339 list_remove(&gdiFont->entry);
4340 LeaveCriticalSection( &freetype_cs );
4346 TRACE("destroying hfont=%p\n", handle);
4348 dump_gdi_font_list();
4350 font_elem_ptr = list_head(&gdi_font_list);
4351 while(font_elem_ptr) {
4352 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4353 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4355 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4356 while(hfontlist_elem_ptr) {
4357 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4358 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4359 if(hflist->hfont == handle) {
4360 list_remove(&hflist->entry);
4361 HeapFree(GetProcessHeap(), 0, hflist);
4365 if(list_empty(&gdiFont->hfontlist)) {
4366 TRACE("Moving to Unused list\n");
4367 list_remove(&gdiFont->entry);
4368 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4373 font_elem_ptr = list_head(&unused_gdi_font_list);
4374 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4375 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4376 while(font_elem_ptr) {
4377 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4378 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4379 TRACE("freeing %p\n", gdiFont);
4380 list_remove(&gdiFont->entry);
4383 LeaveCriticalSection( &freetype_cs );
4387 /***************************************************
4388 * create_enum_charset_list
4390 * This function creates charset enumeration list because in DEFAULT_CHARSET
4391 * case, the ANSI codepage's charset takes precedence over other charsets.
4392 * This function works as a filter other than DEFAULT_CHARSET case.
4394 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4399 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4400 csi.fs.fsCsb[0] != 0) {
4401 list->element[n].mask = csi.fs.fsCsb[0];
4402 list->element[n].charset = csi.ciCharset;
4403 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4406 else { /* charset is DEFAULT_CHARSET or invalid. */
4409 /* Set the current codepage's charset as the first element. */
4411 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4412 csi.fs.fsCsb[0] != 0) {
4413 list->element[n].mask = csi.fs.fsCsb[0];
4414 list->element[n].charset = csi.ciCharset;
4415 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4419 /* Fill out left elements. */
4420 for (i = 0; i < 32; i++) {
4422 fs.fsCsb[0] = 1L << i;
4424 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4425 continue; /* skip, already added. */
4426 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4427 continue; /* skip, this is an invalid fsCsb bit. */
4429 list->element[n].mask = fs.fsCsb[0];
4430 list->element[n].charset = csi.ciCharset;
4431 list->element[n].name = ElfScriptsW[i];
4440 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4441 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4446 if (face->cached_enum_data)
4449 *pelf = face->cached_enum_data->elf;
4450 *pntm = face->cached_enum_data->ntm;
4451 *ptype = face->cached_enum_data->type;
4455 font = alloc_font();
4457 if(face->scalable) {
4458 height = -2048; /* 2048 is the most common em size */
4461 height = face->size.y_ppem >> 6;
4462 width = face->size.x_ppem >> 6;
4464 font->scale_y = 1.0;
4466 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4472 font->name = strdupW(face->family->FamilyName);
4473 font->ntmFlags = face->ntmFlags;
4475 if (get_outline_text_metrics(font))
4477 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4479 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4481 lstrcpynW(pelf->elfLogFont.lfFaceName,
4482 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4484 lstrcpynW(pelf->elfFullName,
4485 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4487 lstrcpynW(pelf->elfStyle,
4488 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4493 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4495 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4497 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4499 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4501 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4502 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4505 pntm->ntmTm.ntmFlags = face->ntmFlags;
4506 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4507 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4508 pntm->ntmFontSig = face->fs;
4510 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4512 pelf->elfLogFont.lfEscapement = 0;
4513 pelf->elfLogFont.lfOrientation = 0;
4514 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4515 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4516 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4517 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4518 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4519 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4520 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4521 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4522 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4523 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4524 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4527 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4528 *ptype |= TRUETYPE_FONTTYPE;
4529 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4530 *ptype |= DEVICE_FONTTYPE;
4531 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4532 *ptype |= RASTER_FONTTYPE;
4534 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4535 if (face->cached_enum_data)
4537 face->cached_enum_data->elf = *pelf;
4538 face->cached_enum_data->ntm = *pntm;
4539 face->cached_enum_data->type = *ptype;
4545 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4547 struct list *face_elem_ptr;
4549 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4551 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4553 static const WCHAR spaceW[] = { ' ',0 };
4554 WCHAR full_family_name[LF_FULLFACESIZE];
4555 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4557 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4559 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4560 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4564 strcpyW(full_family_name, family->FamilyName);
4565 strcatW(full_family_name, spaceW);
4566 strcatW(full_family_name, face->StyleName);
4567 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4573 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4575 static const WCHAR spaceW[] = { ' ',0 };
4576 WCHAR full_family_name[LF_FULLFACESIZE];
4578 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4580 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4582 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4583 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4587 strcpyW(full_family_name, face->family->FamilyName);
4588 strcatW(full_family_name, spaceW);
4589 strcatW(full_family_name, face->StyleName);
4590 return !strcmpiW(lf->lfFaceName, full_family_name);
4593 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4594 FONTENUMPROCW proc, LPARAM lparam)
4597 NEWTEXTMETRICEXW ntm;
4601 GetEnumStructs(face, &elf, &ntm, &type);
4602 for(i = 0; i < list->total; i++) {
4603 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4604 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4605 strcpyW(elf.elfScript, OEM_DOSW);
4606 i = 32; /* break out of loop */
4607 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4610 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4611 if(list->element[i].name)
4612 strcpyW(elf.elfScript, list->element[i].name);
4614 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4616 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4617 debugstr_w(elf.elfLogFont.lfFaceName),
4618 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4619 list->element[i].charset, type, debugstr_w(elf.elfScript),
4620 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4621 ntm.ntmTm.ntmFlags);
4622 /* release section before callback (FIXME) */
4623 LeaveCriticalSection( &freetype_cs );
4624 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4625 EnterCriticalSection( &freetype_cs );
4630 /*************************************************************
4631 * freetype_EnumFonts
4633 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4637 struct list *family_elem_ptr, *face_elem_ptr;
4639 struct enum_charset_list enum_charsets;
4643 lf.lfCharSet = DEFAULT_CHARSET;
4644 lf.lfPitchAndFamily = 0;
4645 lf.lfFaceName[0] = 0;
4649 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4651 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4654 EnterCriticalSection( &freetype_cs );
4655 if(plf->lfFaceName[0]) {
4657 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4660 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4661 debugstr_w(psub->to.name));
4663 strcpyW(lf.lfFaceName, psub->to.name);
4667 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4668 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4669 if(family_matches(family, plf)) {
4670 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4671 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4672 if (!face_matches(face, plf)) continue;
4673 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4678 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4679 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4680 face_elem_ptr = list_head(&family->faces);
4681 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4682 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4685 LeaveCriticalSection( &freetype_cs );
4689 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4691 pt->x.value = vec->x >> 6;
4692 pt->x.fract = (vec->x & 0x3f) << 10;
4693 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4694 pt->y.value = vec->y >> 6;
4695 pt->y.fract = (vec->y & 0x3f) << 10;
4696 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4700 /***************************************************
4701 * According to the MSDN documentation on WideCharToMultiByte,
4702 * certain codepages cannot set the default_used parameter.
4703 * This returns TRUE if the codepage can set that parameter, false else
4704 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4706 static BOOL codepage_sets_default_used(UINT codepage)
4720 * GSUB Table handling functions
4723 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4725 const GSUB_CoverageFormat1* cf1;
4729 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4731 int count = GET_BE_WORD(cf1->GlyphCount);
4733 TRACE("Coverage Format 1, %i glyphs\n",count);
4734 for (i = 0; i < count; i++)
4735 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4739 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4741 const GSUB_CoverageFormat2* cf2;
4744 cf2 = (const GSUB_CoverageFormat2*)cf1;
4746 count = GET_BE_WORD(cf2->RangeCount);
4747 TRACE("Coverage Format 2, %i ranges\n",count);
4748 for (i = 0; i < count; i++)
4750 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4752 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4753 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4755 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4756 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4762 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4767 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4769 const GSUB_ScriptList *script;
4770 const GSUB_Script *deflt = NULL;
4772 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4774 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4775 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4777 const GSUB_Script *scr;
4780 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4781 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4783 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4785 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4791 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4795 const GSUB_LangSys *Lang;
4797 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4799 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4801 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4802 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4804 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4807 offset = GET_BE_WORD(script->DefaultLangSys);
4810 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4816 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4819 const GSUB_FeatureList *feature;
4820 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4822 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4823 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4825 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4826 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4828 const GSUB_Feature *feat;
4829 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4836 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4840 const GSUB_LookupList *lookup;
4841 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4843 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4844 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4846 const GSUB_LookupTable *look;
4847 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4848 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4849 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4850 if (GET_BE_WORD(look->LookupType) != 1)
4851 FIXME("We only handle SubType 1\n");
4856 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4858 const GSUB_SingleSubstFormat1 *ssf1;
4859 offset = GET_BE_WORD(look->SubTable[j]);
4860 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4861 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4863 int offset = GET_BE_WORD(ssf1->Coverage);
4864 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4865 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4867 TRACE(" Glyph 0x%x ->",glyph);
4868 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4869 TRACE(" 0x%x\n",glyph);
4874 const GSUB_SingleSubstFormat2 *ssf2;
4878 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4879 offset = GET_BE_WORD(ssf1->Coverage);
4880 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4881 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4882 TRACE(" Coverage index %i\n",index);
4885 TRACE(" Glyph is 0x%x ->",glyph);
4886 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4887 TRACE("0x%x\n",glyph);
4896 static const char* get_opentype_script(const GdiFont *font)
4899 * I am not sure if this is the correct way to generate our script tag
4902 switch (font->charset)
4904 case ANSI_CHARSET: return "latn";
4905 case BALTIC_CHARSET: return "latn"; /* ?? */
4906 case CHINESEBIG5_CHARSET: return "hani";
4907 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4908 case GB2312_CHARSET: return "hani";
4909 case GREEK_CHARSET: return "grek";
4910 case HANGUL_CHARSET: return "hang";
4911 case RUSSIAN_CHARSET: return "cyrl";
4912 case SHIFTJIS_CHARSET: return "kana";
4913 case TURKISH_CHARSET: return "latn"; /* ?? */
4914 case VIETNAMESE_CHARSET: return "latn";
4915 case JOHAB_CHARSET: return "latn"; /* ?? */
4916 case ARABIC_CHARSET: return "arab";
4917 case HEBREW_CHARSET: return "hebr";
4918 case THAI_CHARSET: return "thai";
4919 default: return "latn";
4923 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4925 const GSUB_Header *header;
4926 const GSUB_Script *script;
4927 const GSUB_LangSys *language;
4928 const GSUB_Feature *feature;
4930 if (!font->GSUB_Table)
4933 header = font->GSUB_Table;
4935 script = GSUB_get_script_table(header, get_opentype_script(font));
4938 TRACE("Script not found\n");
4941 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4944 TRACE("Language not found\n");
4947 feature = GSUB_get_feature(header, language, "vrt2");
4949 feature = GSUB_get_feature(header, language, "vert");
4952 TRACE("vrt2/vert feature not found\n");
4955 return GSUB_apply_feature(header, feature, glyph);
4958 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4962 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4963 WCHAR wc = (WCHAR)glyph;
4965 BOOL *default_used_pointer;
4968 default_used_pointer = NULL;
4969 default_used = FALSE;
4970 if (codepage_sets_default_used(font->codepage))
4971 default_used_pointer = &default_used;
4972 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4975 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4976 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4977 return get_GSUB_vert_glyph(font,ret);
4980 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4982 if (glyph < 0x100) glyph += 0xf000;
4983 /* there is a number of old pre-Unicode "broken" TTFs, which
4984 do have symbols at U+00XX instead of U+f0XX */
4985 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4986 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4988 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4990 return get_GSUB_vert_glyph(font,glyphId);
4993 /*************************************************************
4994 * freetype_GetGlyphIndices
4996 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
4998 struct freetype_physdev *physdev = get_freetype_dev( dev );
5001 BOOL got_default = FALSE;
5005 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5006 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5009 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5011 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5016 EnterCriticalSection( &freetype_cs );
5018 for(i = 0; i < count; i++)
5020 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5025 if (FT_IS_SFNT(physdev->font->ft_face))
5027 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5028 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5033 get_text_metrics(physdev->font, &textm);
5034 default_char = textm.tmDefaultChar;
5038 pgi[i] = default_char;
5041 LeaveCriticalSection( &freetype_cs );
5045 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5047 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5048 return !memcmp(matrix, &identity, sizeof(FMAT2));
5051 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5053 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5054 return !memcmp(matrix, &identity, sizeof(MAT2));
5057 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5058 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5061 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5062 FT_Face ft_face = incoming_font->ft_face;
5063 GdiFont *font = incoming_font;
5064 FT_UInt glyph_index;
5065 DWORD width, height, pitch, needed = 0;
5066 FT_Bitmap ft_bitmap;
5068 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5070 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5071 double widthRatio = 1.0;
5072 FT_Matrix transMat = identityMat;
5073 FT_Matrix transMatUnrotated;
5074 BOOL needsTransform = FALSE;
5075 BOOL tategaki = (font->GSUB_Table != NULL);
5076 UINT original_index;
5078 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5079 buflen, buf, lpmat);
5081 TRACE("font transform %f %f %f %f\n",
5082 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5083 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5085 if(format & GGO_GLYPH_INDEX) {
5086 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5087 original_index = glyph;
5088 format &= ~GGO_GLYPH_INDEX;
5090 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5091 ft_face = font->ft_face;
5092 original_index = glyph_index;
5095 if(format & GGO_UNHINTED) {
5096 load_flags |= FT_LOAD_NO_HINTING;
5097 format &= ~GGO_UNHINTED;
5100 /* tategaki never appears to happen to lower glyph index */
5101 if (glyph_index < TATEGAKI_LOWER_BOUND )
5104 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5105 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5106 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5107 font->gmsize * sizeof(GM*));
5109 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5110 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5112 *lpgm = FONT_GM(font,original_index)->gm;
5113 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5114 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5115 lpgm->gmCellIncX, lpgm->gmCellIncY);
5116 return 1; /* FIXME */
5120 if (!font->gm[original_index / GM_BLOCK_SIZE])
5121 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5123 /* Scaling factor */
5128 get_text_metrics(font, &tm);
5130 widthRatio = (double)font->aveWidth;
5131 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5134 widthRatio = font->scale_y;
5136 /* Scaling transform */
5137 if (widthRatio != 1.0 || font->scale_y != 1.0)
5140 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5143 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5145 pFT_Matrix_Multiply(&scaleMat, &transMat);
5146 needsTransform = TRUE;
5149 /* Slant transform */
5150 if (font->fake_italic) {
5153 slantMat.xx = (1 << 16);
5154 slantMat.xy = ((1 << 16) >> 2);
5156 slantMat.yy = (1 << 16);
5157 pFT_Matrix_Multiply(&slantMat, &transMat);
5158 needsTransform = TRUE;
5161 /* Rotation transform */
5162 transMatUnrotated = transMat;
5163 if(font->orientation && !tategaki) {
5164 FT_Matrix rotationMat;
5166 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5167 pFT_Vector_Unit(&vecAngle, angle);
5168 rotationMat.xx = vecAngle.x;
5169 rotationMat.xy = -vecAngle.y;
5170 rotationMat.yx = -rotationMat.xy;
5171 rotationMat.yy = rotationMat.xx;
5173 pFT_Matrix_Multiply(&rotationMat, &transMat);
5174 needsTransform = TRUE;
5177 /* World transform */
5178 if (!is_identity_FMAT2(&font->font_desc.matrix))
5181 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5182 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5183 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5184 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5185 pFT_Matrix_Multiply(&worldMat, &transMat);
5186 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5187 needsTransform = TRUE;
5190 /* Extra transformation specified by caller */
5191 if (!is_identity_MAT2(lpmat))
5194 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5195 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5196 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5197 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5198 pFT_Matrix_Multiply(&extraMat, &transMat);
5199 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5200 needsTransform = TRUE;
5203 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5204 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5205 format == GGO_GRAY8_BITMAP))
5207 load_flags |= FT_LOAD_NO_BITMAP;
5210 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5213 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5217 if(!needsTransform) {
5218 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5219 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5220 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5222 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5223 bottom = (ft_face->glyph->metrics.horiBearingY -
5224 ft_face->glyph->metrics.height) & -64;
5225 lpgm->gmCellIncX = adv;
5226 lpgm->gmCellIncY = 0;
5233 for(xc = 0; xc < 2; xc++) {
5234 for(yc = 0; yc < 2; yc++) {
5235 vec.x = (ft_face->glyph->metrics.horiBearingX +
5236 xc * ft_face->glyph->metrics.width);
5237 vec.y = ft_face->glyph->metrics.horiBearingY -
5238 yc * ft_face->glyph->metrics.height;
5239 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5240 pFT_Vector_Transform(&vec, &transMat);
5241 if(xc == 0 && yc == 0) {
5242 left = right = vec.x;
5243 top = bottom = vec.y;
5245 if(vec.x < left) left = vec.x;
5246 else if(vec.x > right) right = vec.x;
5247 if(vec.y < bottom) bottom = vec.y;
5248 else if(vec.y > top) top = vec.y;
5253 right = (right + 63) & -64;
5254 bottom = bottom & -64;
5255 top = (top + 63) & -64;
5257 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5258 vec.x = ft_face->glyph->metrics.horiAdvance;
5260 pFT_Vector_Transform(&vec, &transMat);
5261 lpgm->gmCellIncX = (vec.x+63) >> 6;
5262 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5264 vec.x = ft_face->glyph->metrics.horiAdvance;
5266 pFT_Vector_Transform(&vec, &transMatUnrotated);
5267 adv = (vec.x+63) >> 6;
5271 bbx = (right - left) >> 6;
5272 lpgm->gmBlackBoxX = (right - left) >> 6;
5273 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5274 lpgm->gmptGlyphOrigin.x = left >> 6;
5275 lpgm->gmptGlyphOrigin.y = top >> 6;
5277 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5278 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5279 lpgm->gmCellIncX, lpgm->gmCellIncY);
5281 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5282 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5284 FONT_GM(font,original_index)->gm = *lpgm;
5285 FONT_GM(font,original_index)->adv = adv;
5286 FONT_GM(font,original_index)->lsb = lsb;
5287 FONT_GM(font,original_index)->bbx = bbx;
5288 FONT_GM(font,original_index)->init = TRUE;
5291 if(format == GGO_METRICS)
5293 return 1; /* FIXME */
5296 if(ft_face->glyph->format != ft_glyph_format_outline &&
5297 (format == GGO_NATIVE || format == GGO_BEZIER ||
5298 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5299 format == GGO_GRAY8_BITMAP))
5301 TRACE("loaded a bitmap\n");
5307 width = lpgm->gmBlackBoxX;
5308 height = lpgm->gmBlackBoxY;
5309 pitch = ((width + 31) >> 5) << 2;
5310 needed = pitch * height;
5312 if(!buf || !buflen) break;
5314 switch(ft_face->glyph->format) {
5315 case ft_glyph_format_bitmap:
5317 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5318 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5319 INT h = ft_face->glyph->bitmap.rows;
5321 memcpy(dst, src, w);
5322 src += ft_face->glyph->bitmap.pitch;
5328 case ft_glyph_format_outline:
5329 ft_bitmap.width = width;
5330 ft_bitmap.rows = height;
5331 ft_bitmap.pitch = pitch;
5332 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5333 ft_bitmap.buffer = buf;
5336 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5338 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5340 /* Note: FreeType will only set 'black' bits for us. */
5341 memset(buf, 0, needed);
5342 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5346 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5351 case GGO_GRAY2_BITMAP:
5352 case GGO_GRAY4_BITMAP:
5353 case GGO_GRAY8_BITMAP:
5354 case WINE_GGO_GRAY16_BITMAP:
5356 unsigned int mult, row, col;
5359 width = lpgm->gmBlackBoxX;
5360 height = lpgm->gmBlackBoxY;
5361 pitch = (width + 3) / 4 * 4;
5362 needed = pitch * height;
5364 if(!buf || !buflen) break;
5366 switch(ft_face->glyph->format) {
5367 case ft_glyph_format_bitmap:
5369 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5370 INT h = ft_face->glyph->bitmap.rows;
5372 memset( buf, 0, needed );
5374 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5375 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
5376 src += ft_face->glyph->bitmap.pitch;
5381 case ft_glyph_format_outline:
5383 ft_bitmap.width = width;
5384 ft_bitmap.rows = height;
5385 ft_bitmap.pitch = pitch;
5386 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5387 ft_bitmap.buffer = buf;
5390 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5392 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5394 memset(ft_bitmap.buffer, 0, buflen);
5396 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5398 if(format == GGO_GRAY2_BITMAP)
5400 else if(format == GGO_GRAY4_BITMAP)
5402 else if(format == GGO_GRAY8_BITMAP)
5404 else /* format == WINE_GGO_GRAY16_BITMAP */
5409 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5414 for(row = 0; row < height; row++) {
5416 for(col = 0; col < width; col++, ptr++) {
5417 *ptr = (((int)*ptr) * mult + 128) / 256;
5424 case WINE_GGO_HRGB_BITMAP:
5425 case WINE_GGO_HBGR_BITMAP:
5426 case WINE_GGO_VRGB_BITMAP:
5427 case WINE_GGO_VBGR_BITMAP:
5428 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5430 switch (ft_face->glyph->format)
5432 case FT_GLYPH_FORMAT_BITMAP:
5437 width = lpgm->gmBlackBoxX;
5438 height = lpgm->gmBlackBoxY;
5440 needed = pitch * height;
5442 if (!buf || !buflen) break;
5444 memset(buf, 0, buflen);
5446 src = ft_face->glyph->bitmap.buffer;
5447 src_pitch = ft_face->glyph->bitmap.pitch;
5449 height = min( height, ft_face->glyph->bitmap.rows );
5452 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5454 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5455 ((unsigned int *)dst)[x] = ~0u;
5464 case FT_GLYPH_FORMAT_OUTLINE:
5468 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5469 INT x_shift, y_shift;
5471 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5472 FT_Render_Mode render_mode =
5473 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5474 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5476 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5478 if ( render_mode == FT_RENDER_MODE_LCD)
5480 lpgm->gmBlackBoxX += 2;
5481 lpgm->gmptGlyphOrigin.x -= 1;
5485 lpgm->gmBlackBoxY += 2;
5486 lpgm->gmptGlyphOrigin.y += 1;
5490 width = lpgm->gmBlackBoxX;
5491 height = lpgm->gmBlackBoxY;
5493 needed = pitch * height;
5495 if (!buf || !buflen) break;
5497 memset(buf, 0, buflen);
5499 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5501 if ( needsTransform )
5502 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5504 if ( pFT_Library_SetLcdFilter )
5505 pFT_Library_SetLcdFilter( library, lcdfilter );
5506 pFT_Render_Glyph (ft_face->glyph, render_mode);
5508 src = ft_face->glyph->bitmap.buffer;
5509 src_pitch = ft_face->glyph->bitmap.pitch;
5510 src_width = ft_face->glyph->bitmap.width;
5511 src_height = ft_face->glyph->bitmap.rows;
5513 if ( render_mode == FT_RENDER_MODE_LCD)
5521 rgb_interval = src_pitch;
5526 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5527 if ( x_shift < 0 ) x_shift = 0;
5528 if ( x_shift + (src_width / hmul) > width )
5529 x_shift = width - (src_width / hmul);
5531 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5532 if ( y_shift < 0 ) y_shift = 0;
5533 if ( y_shift + (src_height / vmul) > height )
5534 y_shift = height - (src_height / vmul);
5536 dst += x_shift + y_shift * ( pitch / 4 );
5537 while ( src_height )
5539 for ( x = 0; x < src_width / hmul; x++ )
5543 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5544 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5545 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5546 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5550 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5551 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5552 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5553 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5556 src += src_pitch * vmul;
5565 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5577 int contour, point = 0, first_pt;
5578 FT_Outline *outline = &ft_face->glyph->outline;
5579 TTPOLYGONHEADER *pph;
5581 DWORD pph_start, cpfx, type;
5583 if(buflen == 0) buf = NULL;
5585 if (needsTransform && buf) {
5586 pFT_Outline_Transform(outline, &transMat);
5589 for(contour = 0; contour < outline->n_contours; contour++) {
5591 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5594 pph->dwType = TT_POLYGON_TYPE;
5595 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5597 needed += sizeof(*pph);
5599 while(point <= outline->contours[contour]) {
5600 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5601 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5602 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5606 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5609 } while(point <= outline->contours[contour] &&
5610 (outline->tags[point] & FT_Curve_Tag_On) ==
5611 (outline->tags[point-1] & FT_Curve_Tag_On));
5612 /* At the end of a contour Windows adds the start point, but
5614 if(point > outline->contours[contour] &&
5615 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5617 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5619 } else if(point <= outline->contours[contour] &&
5620 outline->tags[point] & FT_Curve_Tag_On) {
5621 /* add closing pt for bezier */
5623 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5631 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5634 pph->cb = needed - pph_start;
5640 /* Convert the quadratic Beziers to cubic Beziers.
5641 The parametric eqn for a cubic Bezier is, from PLRM:
5642 r(t) = at^3 + bt^2 + ct + r0
5643 with the control points:
5648 A quadratic Bezier has the form:
5649 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5651 So equating powers of t leads to:
5652 r1 = 2/3 p1 + 1/3 p0
5653 r2 = 2/3 p1 + 1/3 p2
5654 and of course r0 = p0, r3 = p2
5657 int contour, point = 0, first_pt;
5658 FT_Outline *outline = &ft_face->glyph->outline;
5659 TTPOLYGONHEADER *pph;
5661 DWORD pph_start, cpfx, type;
5662 FT_Vector cubic_control[4];
5663 if(buflen == 0) buf = NULL;
5665 if (needsTransform && buf) {
5666 pFT_Outline_Transform(outline, &transMat);
5669 for(contour = 0; contour < outline->n_contours; contour++) {
5671 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5674 pph->dwType = TT_POLYGON_TYPE;
5675 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5677 needed += sizeof(*pph);
5679 while(point <= outline->contours[contour]) {
5680 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5681 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5682 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5685 if(type == TT_PRIM_LINE) {
5687 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5691 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5694 /* FIXME: Possible optimization in endpoint calculation
5695 if there are two consecutive curves */
5696 cubic_control[0] = outline->points[point-1];
5697 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5698 cubic_control[0].x += outline->points[point].x + 1;
5699 cubic_control[0].y += outline->points[point].y + 1;
5700 cubic_control[0].x >>= 1;
5701 cubic_control[0].y >>= 1;
5703 if(point+1 > outline->contours[contour])
5704 cubic_control[3] = outline->points[first_pt];
5706 cubic_control[3] = outline->points[point+1];
5707 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5708 cubic_control[3].x += outline->points[point].x + 1;
5709 cubic_control[3].y += outline->points[point].y + 1;
5710 cubic_control[3].x >>= 1;
5711 cubic_control[3].y >>= 1;
5714 /* r1 = 1/3 p0 + 2/3 p1
5715 r2 = 1/3 p2 + 2/3 p1 */
5716 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5717 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5718 cubic_control[2] = cubic_control[1];
5719 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5720 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5721 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5722 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5724 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5725 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5726 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5731 } while(point <= outline->contours[contour] &&
5732 (outline->tags[point] & FT_Curve_Tag_On) ==
5733 (outline->tags[point-1] & FT_Curve_Tag_On));
5734 /* At the end of a contour Windows adds the start point,
5735 but only for Beziers and we've already done that.
5737 if(point <= outline->contours[contour] &&
5738 outline->tags[point] & FT_Curve_Tag_On) {
5739 /* This is the closing pt of a bezier, but we've already
5740 added it, so just inc point and carry on */
5747 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5750 pph->cb = needed - pph_start;
5756 FIXME("Unsupported format %d\n", format);
5762 static BOOL get_bitmap_text_metrics(GdiFont *font)
5764 FT_Face ft_face = font->ft_face;
5765 FT_WinFNT_HeaderRec winfnt_header;
5766 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5767 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5768 font->potm->otmSize = size;
5770 #define TM font->potm->otmTextMetrics
5771 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5773 TM.tmHeight = winfnt_header.pixel_height;
5774 TM.tmAscent = winfnt_header.ascent;
5775 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5776 TM.tmInternalLeading = winfnt_header.internal_leading;
5777 TM.tmExternalLeading = winfnt_header.external_leading;
5778 TM.tmAveCharWidth = winfnt_header.avg_width;
5779 TM.tmMaxCharWidth = winfnt_header.max_width;
5780 TM.tmWeight = winfnt_header.weight;
5782 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5783 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5784 TM.tmFirstChar = winfnt_header.first_char;
5785 TM.tmLastChar = winfnt_header.last_char;
5786 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5787 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5788 TM.tmItalic = winfnt_header.italic;
5789 TM.tmUnderlined = font->underline;
5790 TM.tmStruckOut = font->strikeout;
5791 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5792 TM.tmCharSet = winfnt_header.charset;
5796 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5797 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5798 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5799 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5800 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5801 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5802 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5803 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5805 TM.tmDigitizedAspectX = 96; /* FIXME */
5806 TM.tmDigitizedAspectY = 96; /* FIXME */
5808 TM.tmLastChar = 255;
5809 TM.tmDefaultChar = 32;
5810 TM.tmBreakChar = 32;
5811 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5812 TM.tmUnderlined = font->underline;
5813 TM.tmStruckOut = font->strikeout;
5814 /* NB inverted meaning of TMPF_FIXED_PITCH */
5815 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5816 TM.tmCharSet = font->charset;
5824 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5826 double scale_x, scale_y;
5830 scale_x = (double)font->aveWidth;
5831 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5834 scale_x = font->scale_y;
5836 scale_x *= fabs(font->font_desc.matrix.eM11);
5837 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5839 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5840 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5842 SCALE_Y(ptm->tmHeight);
5843 SCALE_Y(ptm->tmAscent);
5844 SCALE_Y(ptm->tmDescent);
5845 SCALE_Y(ptm->tmInternalLeading);
5846 SCALE_Y(ptm->tmExternalLeading);
5847 SCALE_Y(ptm->tmOverhang);
5849 SCALE_X(ptm->tmAveCharWidth);
5850 SCALE_X(ptm->tmMaxCharWidth);
5856 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5858 double scale_x, scale_y;
5862 scale_x = (double)font->aveWidth;
5863 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5866 scale_x = font->scale_y;
5868 scale_x *= fabs(font->font_desc.matrix.eM11);
5869 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5871 scale_font_metrics(font, &potm->otmTextMetrics);
5873 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5874 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5876 SCALE_Y(potm->otmAscent);
5877 SCALE_Y(potm->otmDescent);
5878 SCALE_Y(potm->otmLineGap);
5879 SCALE_Y(potm->otmsCapEmHeight);
5880 SCALE_Y(potm->otmsXHeight);
5881 SCALE_Y(potm->otmrcFontBox.top);
5882 SCALE_Y(potm->otmrcFontBox.bottom);
5883 SCALE_X(potm->otmrcFontBox.left);
5884 SCALE_X(potm->otmrcFontBox.right);
5885 SCALE_Y(potm->otmMacAscent);
5886 SCALE_Y(potm->otmMacDescent);
5887 SCALE_Y(potm->otmMacLineGap);
5888 SCALE_X(potm->otmptSubscriptSize.x);
5889 SCALE_Y(potm->otmptSubscriptSize.y);
5890 SCALE_X(potm->otmptSubscriptOffset.x);
5891 SCALE_Y(potm->otmptSubscriptOffset.y);
5892 SCALE_X(potm->otmptSuperscriptSize.x);
5893 SCALE_Y(potm->otmptSuperscriptSize.y);
5894 SCALE_X(potm->otmptSuperscriptOffset.x);
5895 SCALE_Y(potm->otmptSuperscriptOffset.y);
5896 SCALE_Y(potm->otmsStrikeoutSize);
5897 SCALE_Y(potm->otmsStrikeoutPosition);
5898 SCALE_Y(potm->otmsUnderscoreSize);
5899 SCALE_Y(potm->otmsUnderscorePosition);
5905 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5909 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5911 /* Make sure that the font has sane width/height ratio */
5914 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5916 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5921 *ptm = font->potm->otmTextMetrics;
5922 scale_font_metrics(font, ptm);
5926 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5930 for(i = 0; i < ft_face->num_charmaps; i++)
5932 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5938 static BOOL get_outline_text_metrics(GdiFont *font)
5941 FT_Face ft_face = font->ft_face;
5942 UINT needed, lenfam, lensty;
5944 TT_HoriHeader *pHori;
5945 TT_Postscript *pPost;
5946 FT_Fixed x_scale, y_scale;
5947 WCHAR *family_nameW, *style_nameW;
5948 static const WCHAR spaceW[] = {' ', '\0'};
5950 INT ascent, descent;
5952 TRACE("font=%p\n", font);
5954 if(!FT_IS_SCALABLE(ft_face))
5957 needed = sizeof(*font->potm);
5959 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5960 family_nameW = strdupW(font->name);
5962 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5964 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5965 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5966 style_nameW, lensty/sizeof(WCHAR));
5968 /* These names should be read from the TT name table */
5970 /* length of otmpFamilyName */
5973 /* length of otmpFaceName */
5974 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5975 needed += lenfam; /* just the family name */
5977 needed += lenfam + lensty; /* family + " " + style */
5980 /* length of otmpStyleName */
5983 /* length of otmpFullName */
5984 needed += lenfam + lensty;
5987 x_scale = ft_face->size->metrics.x_scale;
5988 y_scale = ft_face->size->metrics.y_scale;
5990 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5992 FIXME("Can't find OS/2 table - not TT font?\n");
5996 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5998 FIXME("Can't find HHEA table - not TT font?\n");
6002 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6004 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",
6005 pOS2->usWinAscent, pOS2->usWinDescent,
6006 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6007 ft_face->ascender, ft_face->descender, ft_face->height,
6008 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6009 ft_face->bbox.yMax, ft_face->bbox.yMin);
6011 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6012 font->potm->otmSize = needed;
6014 #define TM font->potm->otmTextMetrics
6016 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6017 ascent = pHori->Ascender;
6018 descent = -pHori->Descender;
6020 ascent = pOS2->usWinAscent;
6021 descent = pOS2->usWinDescent;
6025 TM.tmAscent = font->yMax;
6026 TM.tmDescent = -font->yMin;
6027 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6029 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6030 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6031 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6032 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6035 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6038 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6040 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6041 ((ascent + descent) -
6042 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6044 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6045 if (TM.tmAveCharWidth == 0) {
6046 TM.tmAveCharWidth = 1;
6048 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6049 TM.tmWeight = FW_REGULAR;
6050 if (font->fake_bold)
6051 TM.tmWeight = FW_BOLD;
6054 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6056 if (pOS2->usWeightClass > FW_MEDIUM)
6057 TM.tmWeight = pOS2->usWeightClass;
6059 else if (pOS2->usWeightClass <= FW_MEDIUM)
6060 TM.tmWeight = pOS2->usWeightClass;
6063 TM.tmDigitizedAspectX = 300;
6064 TM.tmDigitizedAspectY = 300;
6065 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6066 * symbol range to 0 - f0ff
6069 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6074 case 1257: /* Baltic */
6075 TM.tmLastChar = 0xf8fd;
6078 TM.tmLastChar = 0xf0ff;
6080 TM.tmBreakChar = 0x20;
6081 TM.tmDefaultChar = 0x1f;
6085 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6086 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6088 if(pOS2->usFirstCharIndex <= 1)
6089 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6090 else if (pOS2->usFirstCharIndex > 0xff)
6091 TM.tmBreakChar = 0x20;
6093 TM.tmBreakChar = pOS2->usFirstCharIndex;
6094 TM.tmDefaultChar = TM.tmBreakChar - 1;
6096 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6097 TM.tmUnderlined = font->underline;
6098 TM.tmStruckOut = font->strikeout;
6100 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6101 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6102 (pOS2->version == 0xFFFFU ||
6103 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6104 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6106 TM.tmPitchAndFamily = 0;
6108 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6110 case PAN_FAMILY_SCRIPT:
6111 TM.tmPitchAndFamily |= FF_SCRIPT;
6114 case PAN_FAMILY_DECORATIVE:
6115 TM.tmPitchAndFamily |= FF_DECORATIVE;
6120 case PAN_FAMILY_TEXT_DISPLAY:
6121 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6122 /* which is clearly not what the panose spec says. */
6124 if(TM.tmPitchAndFamily == 0 || /* fixed */
6125 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6126 TM.tmPitchAndFamily = FF_MODERN;
6129 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6134 TM.tmPitchAndFamily |= FF_DONTCARE;
6137 case PAN_SERIF_COVE:
6138 case PAN_SERIF_OBTUSE_COVE:
6139 case PAN_SERIF_SQUARE_COVE:
6140 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6141 case PAN_SERIF_SQUARE:
6142 case PAN_SERIF_THIN:
6143 case PAN_SERIF_BONE:
6144 case PAN_SERIF_EXAGGERATED:
6145 case PAN_SERIF_TRIANGLE:
6146 TM.tmPitchAndFamily |= FF_ROMAN;
6149 case PAN_SERIF_NORMAL_SANS:
6150 case PAN_SERIF_OBTUSE_SANS:
6151 case PAN_SERIF_PERP_SANS:
6152 case PAN_SERIF_FLARED:
6153 case PAN_SERIF_ROUNDED:
6154 TM.tmPitchAndFamily |= FF_SWISS;
6161 if(FT_IS_SCALABLE(ft_face))
6162 TM.tmPitchAndFamily |= TMPF_VECTOR;
6164 if(FT_IS_SFNT(ft_face))
6166 if (font->ntmFlags & NTM_PS_OPENTYPE)
6167 TM.tmPitchAndFamily |= TMPF_DEVICE;
6169 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6172 TM.tmCharSet = font->charset;
6174 font->potm->otmFiller = 0;
6175 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6176 font->potm->otmfsSelection = pOS2->fsSelection;
6177 font->potm->otmfsType = pOS2->fsType;
6178 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6179 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6180 font->potm->otmItalicAngle = 0; /* POST table */
6181 font->potm->otmEMSquare = ft_face->units_per_EM;
6182 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6183 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6184 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6185 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6186 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6187 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6188 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6189 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6190 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6191 font->potm->otmMacAscent = TM.tmAscent;
6192 font->potm->otmMacDescent = -TM.tmDescent;
6193 font->potm->otmMacLineGap = font->potm->otmLineGap;
6194 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6195 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6196 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6197 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6198 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6199 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6200 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6201 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6202 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6203 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6204 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6206 font->potm->otmsUnderscoreSize = 0;
6207 font->potm->otmsUnderscorePosition = 0;
6209 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6210 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6214 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6215 cp = (char*)font->potm + sizeof(*font->potm);
6216 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6217 strcpyW((WCHAR*)cp, family_nameW);
6219 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6220 strcpyW((WCHAR*)cp, style_nameW);
6222 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6223 strcpyW((WCHAR*)cp, family_nameW);
6224 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6225 strcatW((WCHAR*)cp, spaceW);
6226 strcatW((WCHAR*)cp, style_nameW);
6227 cp += lenfam + lensty;
6230 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6231 strcpyW((WCHAR*)cp, family_nameW);
6232 strcatW((WCHAR*)cp, spaceW);
6233 strcatW((WCHAR*)cp, style_nameW);
6237 HeapFree(GetProcessHeap(), 0, style_nameW);
6238 HeapFree(GetProcessHeap(), 0, family_nameW);
6242 /*************************************************************
6243 * freetype_GetGlyphOutline
6245 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6246 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6248 struct freetype_physdev *physdev = get_freetype_dev( dev );
6253 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6254 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6258 EnterCriticalSection( &freetype_cs );
6259 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6260 LeaveCriticalSection( &freetype_cs );
6264 /*************************************************************
6265 * freetype_GetTextMetrics
6267 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6269 struct freetype_physdev *physdev = get_freetype_dev( dev );
6274 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6275 return dev->funcs->pGetTextMetrics( dev, metrics );
6279 EnterCriticalSection( &freetype_cs );
6280 ret = get_text_metrics( physdev->font, metrics );
6281 LeaveCriticalSection( &freetype_cs );
6285 /*************************************************************
6286 * freetype_GetOutlineTextMetrics
6288 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6290 struct freetype_physdev *physdev = get_freetype_dev( dev );
6295 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6296 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6299 TRACE("font=%p\n", physdev->font);
6301 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6304 EnterCriticalSection( &freetype_cs );
6306 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6308 if(cbSize >= physdev->font->potm->otmSize)
6310 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6311 scale_outline_font_metrics(physdev->font, potm);
6313 ret = physdev->font->potm->otmSize;
6315 LeaveCriticalSection( &freetype_cs );
6319 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6321 HFONTLIST *hfontlist;
6322 child->font = alloc_font();
6323 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6324 if(!child->font->ft_face)
6326 free_font(child->font);
6331 child->font->font_desc = font->font_desc;
6332 child->font->ntmFlags = child->face->ntmFlags;
6333 child->font->orientation = font->orientation;
6334 child->font->scale_y = font->scale_y;
6335 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6336 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6337 child->font->name = strdupW(child->face->family->FamilyName);
6338 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6339 child->font->base_font = font;
6340 list_add_head(&child_font_list, &child->font->entry);
6341 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6345 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6348 CHILD_FONT *child_font;
6351 font = font->base_font;
6353 *linked_font = font;
6355 if((*glyph = get_glyph_index(font, c)))
6358 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6360 if(!child_font->font)
6361 if(!load_child_font(font, child_font))
6364 if(!child_font->font->ft_face)
6366 g = get_glyph_index(child_font->font, c);
6370 *linked_font = child_font->font;
6377 /*************************************************************
6378 * freetype_GetCharWidth
6380 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6382 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6385 FT_UInt glyph_index;
6386 GdiFont *linked_font;
6387 struct freetype_physdev *physdev = get_freetype_dev( dev );
6391 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6392 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6395 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6398 EnterCriticalSection( &freetype_cs );
6399 for(c = firstChar; c <= lastChar; c++) {
6400 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6401 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6402 &gm, 0, NULL, &identity);
6403 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6405 LeaveCriticalSection( &freetype_cs );
6409 /*************************************************************
6410 * freetype_GetCharABCWidths
6412 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6414 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6417 FT_UInt glyph_index;
6418 GdiFont *linked_font;
6419 struct freetype_physdev *physdev = get_freetype_dev( dev );
6423 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6424 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6427 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6429 if(!FT_IS_SCALABLE(physdev->font->ft_face))
6433 EnterCriticalSection( &freetype_cs );
6435 for(c = firstChar; c <= lastChar; c++) {
6436 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6437 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6438 &gm, 0, NULL, &identity);
6439 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6440 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6441 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6442 FONT_GM(linked_font,glyph_index)->bbx;
6444 LeaveCriticalSection( &freetype_cs );
6448 /*************************************************************
6449 * freetype_GetCharABCWidthsI
6451 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6453 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6456 FT_UInt glyph_index;
6457 GdiFont *linked_font;
6458 struct freetype_physdev *physdev = get_freetype_dev( dev );
6462 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6463 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6466 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6470 EnterCriticalSection( &freetype_cs );
6472 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6474 for(c = firstChar; c < firstChar+count; c++) {
6475 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6476 &gm, 0, NULL, &identity);
6477 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6478 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6479 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6480 - FONT_GM(linked_font,c)->bbx;
6483 for(c = 0; c < count; c++) {
6484 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6485 &gm, 0, NULL, &identity);
6486 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6487 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6488 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6489 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6492 LeaveCriticalSection( &freetype_cs );
6496 /*************************************************************
6497 * freetype_GetTextExtentExPoint
6499 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6500 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6502 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6507 FT_UInt glyph_index;
6508 GdiFont *linked_font;
6509 struct freetype_physdev *physdev = get_freetype_dev( dev );
6513 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6514 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6517 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6520 EnterCriticalSection( &freetype_cs );
6523 get_text_metrics( physdev->font, &tm );
6524 size->cy = tm.tmHeight;
6526 for(idx = 0; idx < count; idx++) {
6527 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6528 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6529 &gm, 0, NULL, &identity);
6530 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6532 if (! pnfit || ext <= max_ext) {
6542 LeaveCriticalSection( &freetype_cs );
6543 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6547 /*************************************************************
6548 * freetype_GetTextExtentExPointI
6550 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6551 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6553 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6558 struct freetype_physdev *physdev = get_freetype_dev( dev );
6562 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6563 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6566 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6569 EnterCriticalSection( &freetype_cs );
6572 get_text_metrics(physdev->font, &tm);
6573 size->cy = tm.tmHeight;
6575 for(idx = 0; idx < count; idx++) {
6576 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6577 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6579 if (! pnfit || ext <= max_ext) {
6589 LeaveCriticalSection( &freetype_cs );
6590 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6594 /*************************************************************
6595 * freetype_GetFontData
6597 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6599 struct freetype_physdev *physdev = get_freetype_dev( dev );
6603 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6604 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6607 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6608 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6609 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6611 return get_font_data( physdev->font, table, offset, buf, cbData );
6614 /*************************************************************
6615 * freetype_GetTextFace
6617 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6620 struct freetype_physdev *physdev = get_freetype_dev( dev );
6624 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6625 return dev->funcs->pGetTextFace( dev, count, str );
6628 n = strlenW(physdev->font->name) + 1;
6631 lstrcpynW(str, physdev->font->name, count);
6637 /*************************************************************
6638 * freetype_GetTextCharsetInfo
6640 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6642 struct freetype_physdev *physdev = get_freetype_dev( dev );
6646 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6647 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6649 if (fs) *fs = physdev->font->fs;
6650 return physdev->font->charset;
6653 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6655 GdiFont *font = dc->gdiFont, *linked_font;
6656 struct list *first_hfont;
6660 EnterCriticalSection( &freetype_cs );
6661 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6662 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6663 if(font == linked_font)
6664 *new_hfont = dc->hFont;
6667 first_hfont = list_head(&linked_font->hfontlist);
6668 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6670 LeaveCriticalSection( &freetype_cs );
6674 /* Retrieve a list of supported Unicode ranges for a given font.
6675 * Can be called with NULL gs to calculate the buffer size. Returns
6676 * the number of ranges found.
6678 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6680 DWORD num_ranges = 0;
6682 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6685 FT_ULong char_code, char_code_prev;
6688 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6690 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6691 face->num_glyphs, glyph_code, char_code);
6693 if (!glyph_code) return 0;
6697 gs->ranges[0].wcLow = (USHORT)char_code;
6698 gs->ranges[0].cGlyphs = 0;
6699 gs->cGlyphsSupported = 0;
6705 if (char_code < char_code_prev)
6707 ERR("expected increasing char code from FT_Get_Next_Char\n");
6710 if (char_code - char_code_prev > 1)
6715 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6716 gs->ranges[num_ranges - 1].cGlyphs = 1;
6717 gs->cGlyphsSupported++;
6722 gs->ranges[num_ranges - 1].cGlyphs++;
6723 gs->cGlyphsSupported++;
6725 char_code_prev = char_code;
6726 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6730 FIXME("encoding %u not supported\n", face->charmap->encoding);
6735 /*************************************************************
6736 * freetype_GetFontUnicodeRanges
6738 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6740 struct freetype_physdev *physdev = get_freetype_dev( dev );
6741 DWORD size, num_ranges;
6745 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6746 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6749 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6750 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6753 glyphset->cbThis = size;
6754 glyphset->cRanges = num_ranges;
6755 glyphset->flAccel = 0;
6760 /*************************************************************
6761 * freetype_FontIsLinked
6763 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6765 struct freetype_physdev *physdev = get_freetype_dev( dev );
6770 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6771 return dev->funcs->pFontIsLinked( dev );
6775 EnterCriticalSection( &freetype_cs );
6776 ret = !list_empty(&physdev->font->child_fonts);
6777 LeaveCriticalSection( &freetype_cs );
6781 static BOOL is_hinting_enabled(void)
6783 /* Use the >= 2.2.0 function if available */
6784 if(pFT_Get_TrueType_Engine_Type)
6786 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6787 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6789 #ifdef FT_DRIVER_HAS_HINTER
6794 /* otherwise if we've been compiled with < 2.2.0 headers
6795 use the internal macro */
6796 mod = pFT_Get_Module(library, "truetype");
6797 if(mod && FT_DRIVER_HAS_HINTER(mod))
6805 static BOOL is_subpixel_rendering_enabled( void )
6807 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6808 return pFT_Library_SetLcdFilter &&
6809 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6815 /*************************************************************************
6816 * GetRasterizerCaps (GDI32.@)
6818 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6820 static int hinting = -1;
6821 static int subpixel = -1;
6825 hinting = is_hinting_enabled();
6826 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6829 if ( subpixel == -1 )
6831 subpixel = is_subpixel_rendering_enabled();
6832 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6835 lprs->nSize = sizeof(RASTERIZER_STATUS);
6836 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6838 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6839 lprs->nLanguageID = 0;
6843 /*************************************************************
6844 * freetype_GdiRealizationInfo
6846 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6848 struct freetype_physdev *physdev = get_freetype_dev( dev );
6849 realization_info_t *info = ptr;
6853 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6854 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6857 FIXME("(%p, %p): stub!\n", physdev->font, info);
6860 if(FT_IS_SCALABLE(physdev->font->ft_face))
6863 info->cache_num = physdev->font->cache_num;
6864 info->unknown2 = -1;
6868 /*************************************************************************
6869 * Kerning support for TrueType fonts
6871 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6873 struct TT_kern_table
6879 struct TT_kern_subtable
6888 USHORT horizontal : 1;
6890 USHORT cross_stream: 1;
6891 USHORT override : 1;
6892 USHORT reserved1 : 4;
6898 struct TT_format0_kern_subtable
6902 USHORT entrySelector;
6913 static DWORD parse_format0_kern_subtable(GdiFont *font,
6914 const struct TT_format0_kern_subtable *tt_f0_ks,
6915 const USHORT *glyph_to_char,
6916 KERNINGPAIR *kern_pair, DWORD cPairs)
6919 const struct TT_kern_pair *tt_kern_pair;
6921 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6923 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6925 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6926 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6927 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6929 if (!kern_pair || !cPairs)
6932 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6934 nPairs = min(nPairs, cPairs);
6936 for (i = 0; i < nPairs; i++)
6938 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6939 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6940 /* this algorithm appears to better match what Windows does */
6941 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6942 if (kern_pair->iKernAmount < 0)
6944 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6945 kern_pair->iKernAmount -= font->ppem;
6947 else if (kern_pair->iKernAmount > 0)
6949 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6950 kern_pair->iKernAmount += font->ppem;
6952 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6954 TRACE("left %u right %u value %d\n",
6955 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6959 TRACE("copied %u entries\n", nPairs);
6963 /*************************************************************
6964 * freetype_GetKerningPairs
6966 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
6970 const struct TT_kern_table *tt_kern_table;
6971 const struct TT_kern_subtable *tt_kern_subtable;
6973 USHORT *glyph_to_char;
6975 struct freetype_physdev *physdev = get_freetype_dev( dev );
6977 if (!(font = physdev->font))
6979 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
6980 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
6984 EnterCriticalSection( &freetype_cs );
6985 if (font->total_kern_pairs != (DWORD)-1)
6987 if (cPairs && kern_pair)
6989 cPairs = min(cPairs, font->total_kern_pairs);
6990 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6992 else cPairs = font->total_kern_pairs;
6994 LeaveCriticalSection( &freetype_cs );
6998 font->total_kern_pairs = 0;
7000 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7002 if (length == GDI_ERROR)
7004 TRACE("no kerning data in the font\n");
7005 LeaveCriticalSection( &freetype_cs );
7009 buf = HeapAlloc(GetProcessHeap(), 0, length);
7012 WARN("Out of memory\n");
7013 LeaveCriticalSection( &freetype_cs );
7017 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7019 /* build a glyph index to char code map */
7020 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7023 WARN("Out of memory allocating a glyph index to char code map\n");
7024 HeapFree(GetProcessHeap(), 0, buf);
7025 LeaveCriticalSection( &freetype_cs );
7029 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7035 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7037 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7038 font->ft_face->num_glyphs, glyph_code, char_code);
7042 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7044 /* FIXME: This doesn't match what Windows does: it does some fancy
7045 * things with duplicate glyph index to char code mappings, while
7046 * we just avoid overriding existing entries.
7048 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7049 glyph_to_char[glyph_code] = (USHORT)char_code;
7051 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7058 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7059 for (n = 0; n <= 65535; n++)
7060 glyph_to_char[n] = (USHORT)n;
7063 tt_kern_table = buf;
7064 nTables = GET_BE_WORD(tt_kern_table->nTables);
7065 TRACE("version %u, nTables %u\n",
7066 GET_BE_WORD(tt_kern_table->version), nTables);
7068 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7070 for (i = 0; i < nTables; i++)
7072 struct TT_kern_subtable tt_kern_subtable_copy;
7074 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7075 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7076 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7078 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7079 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7080 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7082 /* According to the TrueType specification this is the only format
7083 * that will be properly interpreted by Windows and OS/2
7085 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7087 DWORD new_chunk, old_total = font->total_kern_pairs;
7089 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7090 glyph_to_char, NULL, 0);
7091 font->total_kern_pairs += new_chunk;
7093 if (!font->kern_pairs)
7094 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7095 font->total_kern_pairs * sizeof(*font->kern_pairs));
7097 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7098 font->total_kern_pairs * sizeof(*font->kern_pairs));
7100 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7101 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7104 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7106 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7109 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7110 HeapFree(GetProcessHeap(), 0, buf);
7112 if (cPairs && kern_pair)
7114 cPairs = min(cPairs, font->total_kern_pairs);
7115 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7117 else cPairs = font->total_kern_pairs;
7119 LeaveCriticalSection( &freetype_cs );
7123 static const struct gdi_dc_funcs freetype_funcs =
7125 NULL, /* pAbortDoc */
7126 NULL, /* pAbortPath */
7127 NULL, /* pAlphaBlend */
7128 NULL, /* pAngleArc */
7131 NULL, /* pBeginPath */
7132 NULL, /* pBlendImage */
7133 NULL, /* pChoosePixelFormat */
7135 NULL, /* pCloseFigure */
7136 NULL, /* pCreateBitmap */
7137 NULL, /* pCreateCompatibleDC */
7138 freetype_CreateDC, /* pCreateDC */
7139 NULL, /* pCreateDIBSection */
7140 NULL, /* pDeleteBitmap */
7141 freetype_DeleteDC, /* pDeleteDC */
7142 NULL, /* pDeleteObject */
7143 NULL, /* pDescribePixelFormat */
7144 NULL, /* pDeviceCapabilities */
7145 NULL, /* pEllipse */
7147 NULL, /* pEndPage */
7148 NULL, /* pEndPath */
7149 freetype_EnumFonts, /* pEnumFonts */
7150 NULL, /* pEnumICMProfiles */
7151 NULL, /* pExcludeClipRect */
7152 NULL, /* pExtDeviceMode */
7153 NULL, /* pExtEscape */
7154 NULL, /* pExtFloodFill */
7155 NULL, /* pExtSelectClipRgn */
7156 NULL, /* pExtTextOut */
7157 NULL, /* pFillPath */
7158 NULL, /* pFillRgn */
7159 NULL, /* pFlattenPath */
7160 freetype_FontIsLinked, /* pFontIsLinked */
7161 NULL, /* pFrameRgn */
7162 NULL, /* pGdiComment */
7163 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7164 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7165 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7166 freetype_GetCharWidth, /* pGetCharWidth */
7167 NULL, /* pGetDeviceCaps */
7168 NULL, /* pGetDeviceGammaRamp */
7169 freetype_GetFontData, /* pGetFontData */
7170 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7171 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7172 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7173 NULL, /* pGetICMProfile */
7174 NULL, /* pGetImage */
7175 freetype_GetKerningPairs, /* pGetKerningPairs */
7176 NULL, /* pGetNearestColor */
7177 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7178 NULL, /* pGetPixel */
7179 NULL, /* pGetPixelFormat */
7180 NULL, /* pGetSystemPaletteEntries */
7181 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7182 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7183 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7184 freetype_GetTextFace, /* pGetTextFace */
7185 freetype_GetTextMetrics, /* pGetTextMetrics */
7186 NULL, /* pIntersectClipRect */
7187 NULL, /* pInvertRgn */
7189 NULL, /* pModifyWorldTransform */
7191 NULL, /* pOffsetClipRgn */
7192 NULL, /* pOffsetViewportOrg */
7193 NULL, /* pOffsetWindowOrg */
7194 NULL, /* pPaintRgn */
7197 NULL, /* pPolyBezier */
7198 NULL, /* pPolyBezierTo */
7199 NULL, /* pPolyDraw */
7200 NULL, /* pPolyPolygon */
7201 NULL, /* pPolyPolyline */
7202 NULL, /* pPolygon */
7203 NULL, /* pPolyline */
7204 NULL, /* pPolylineTo */
7205 NULL, /* pPutImage */
7206 NULL, /* pRealizeDefaultPalette */
7207 NULL, /* pRealizePalette */
7208 NULL, /* pRectangle */
7209 NULL, /* pResetDC */
7210 NULL, /* pRestoreDC */
7211 NULL, /* pRoundRect */
7213 NULL, /* pScaleViewportExt */
7214 NULL, /* pScaleWindowExt */
7215 NULL, /* pSelectBitmap */
7216 NULL, /* pSelectBrush */
7217 NULL, /* pSelectClipPath */
7218 freetype_SelectFont, /* pSelectFont */
7219 NULL, /* pSelectPalette */
7220 NULL, /* pSelectPen */
7221 NULL, /* pSetArcDirection */
7222 NULL, /* pSetBkColor */
7223 NULL, /* pSetBkMode */
7224 NULL, /* pSetDCBrushColor */
7225 NULL, /* pSetDCPenColor */
7226 NULL, /* pSetDIBColorTable */
7227 NULL, /* pSetDIBitsToDevice */
7228 NULL, /* pSetDeviceClipping */
7229 NULL, /* pSetDeviceGammaRamp */
7230 NULL, /* pSetLayout */
7231 NULL, /* pSetMapMode */
7232 NULL, /* pSetMapperFlags */
7233 NULL, /* pSetPixel */
7234 NULL, /* pSetPixelFormat */
7235 NULL, /* pSetPolyFillMode */
7236 NULL, /* pSetROP2 */
7237 NULL, /* pSetRelAbs */
7238 NULL, /* pSetStretchBltMode */
7239 NULL, /* pSetTextAlign */
7240 NULL, /* pSetTextCharacterExtra */
7241 NULL, /* pSetTextColor */
7242 NULL, /* pSetTextJustification */
7243 NULL, /* pSetViewportExt */
7244 NULL, /* pSetViewportOrg */
7245 NULL, /* pSetWindowExt */
7246 NULL, /* pSetWindowOrg */
7247 NULL, /* pSetWorldTransform */
7248 NULL, /* pStartDoc */
7249 NULL, /* pStartPage */
7250 NULL, /* pStretchBlt */
7251 NULL, /* pStretchDIBits */
7252 NULL, /* pStrokeAndFillPath */
7253 NULL, /* pStrokePath */
7254 NULL, /* pSwapBuffers */
7255 NULL, /* pUnrealizePalette */
7256 NULL, /* pWidenPath */
7257 /* OpenGL not supported */
7260 #else /* HAVE_FREETYPE */
7262 /*************************************************************************/
7264 BOOL WineEngInit(void)
7268 BOOL WineEngDestroyFontInstance(HFONT hfont)
7273 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7275 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7279 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7281 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7285 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7287 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7291 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7296 /*************************************************************************
7297 * GetRasterizerCaps (GDI32.@)
7299 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7301 lprs->nSize = sizeof(RASTERIZER_STATUS);
7303 lprs->nLanguageID = 0;
7307 #endif /* HAVE_FREETYPE */