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"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
98 #ifdef HAVE_FT2BUILD_H
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
144 static FT_Library library = 0;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix);
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigSubstitute);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetInteger);
205 MAKE_FUNCPTR(FcPatternGetString);
211 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
212 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
213 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
216 #ifndef ft_encoding_none
217 #define FT_ENCODING_NONE ft_encoding_none
219 #ifndef ft_encoding_ms_symbol
220 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
222 #ifndef ft_encoding_unicode
223 #define FT_ENCODING_UNICODE ft_encoding_unicode
225 #ifndef ft_encoding_apple_roman
226 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
229 #ifdef WORDS_BIGENDIAN
230 #define GET_BE_WORD(x) (x)
232 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
235 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
242 FT_Short internal_leading;
245 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
246 So to let this compile on older versions of FreeType we'll define the
247 new structure here. */
249 FT_Short height, width;
250 FT_Pos size, x_ppem, y_ppem;
256 NEWTEXTMETRICEXW ntm;
260 typedef struct tagFace {
262 unsigned int refcount;
267 DWORD font_data_size;
271 FT_Fixed font_version;
273 Bitmap_Size size; /* set if face is a bitmap */
274 DWORD flags; /* ADDFONT flags */
275 struct tagFamily *family;
276 /* Cached data for Enum */
277 struct enum_data *cached_enum_data;
280 #define ADDFONT_EXTERNAL_FONT 0x01
281 #define ADDFONT_ALLOW_BITMAP 0x02
282 #define ADDFONT_ADD_TO_CACHE 0x04
283 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
284 #define ADDFONT_VERTICAL_FONT 0x10
285 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
287 typedef struct tagFamily {
289 unsigned int refcount;
293 struct list *replacement;
298 ABC abc; /* metrics of the unrotated char */
314 typedef struct tagGdiFont GdiFont;
324 struct list unused_entry;
325 unsigned int refcount;
328 OUTLINETEXTMETRICW *potm;
329 DWORD total_kern_pairs;
330 KERNINGPAIR *kern_pairs;
331 struct list child_fonts;
333 /* the following members can be accessed without locking, they are never modified after creation */
335 struct font_mapping *mapping;
351 UINT ntmCellHeight, ntmAvgWidth;
360 const WCHAR *font_name;
365 struct enum_charset_element {
368 WCHAR name[LF_FACESIZE];
371 struct enum_charset_list {
373 struct enum_charset_element element[32];
376 #define GM_BLOCK_SIZE 128
377 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
379 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
380 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
381 static unsigned int unused_font_count;
382 #define UNUSED_CACHE_SIZE 10
383 static struct list system_links = LIST_INIT(system_links);
385 static struct list font_subst_list = LIST_INIT(font_subst_list);
387 static struct list font_list = LIST_INIT(font_list);
389 struct freetype_physdev
391 struct gdi_physdev dev;
395 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
397 return (struct freetype_physdev *)dev;
400 static const struct gdi_dc_funcs freetype_funcs;
402 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
403 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
404 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
406 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
407 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
408 'W','i','n','d','o','w','s','\\',
409 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
410 'F','o','n','t','s','\0'};
412 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
413 'W','i','n','d','o','w','s',' ','N','T','\\',
414 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
415 'F','o','n','t','s','\0'};
417 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
418 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
419 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
420 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
422 static const WCHAR * const SystemFontValues[] = {
429 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
430 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
432 /* Interesting and well-known (frequently-assumed!) font names */
433 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
434 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 };
435 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
436 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
437 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
438 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
439 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
440 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
442 static const WCHAR arial[] = {'A','r','i','a','l',0};
443 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
444 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};
445 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};
446 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
447 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
448 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
449 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
450 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
451 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
453 static const WCHAR *default_serif_list[] =
457 bitstream_vera_serif,
461 static const WCHAR *default_fixed_list[] =
465 bitstream_vera_sans_mono,
469 static const WCHAR *default_sans_list[] =
482 typedef struct tagFontSubst {
488 /* Registry font cache key and value names */
489 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
490 'F','o','n','t','s',0};
491 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
492 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
493 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
494 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
495 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
496 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
497 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
498 static const WCHAR face_size_value[] = {'S','i','z','e',0};
499 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
500 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
501 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
502 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
503 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
504 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
505 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
518 static struct list mappings_list = LIST_INIT( mappings_list );
520 static UINT default_aa_flags;
521 static HKEY hkey_font_cache;
523 static CRITICAL_SECTION freetype_cs;
524 static CRITICAL_SECTION_DEBUG critsect_debug =
527 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
528 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
530 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
532 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
534 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
535 static BOOL use_default_fallback = FALSE;
537 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
538 static BOOL get_outline_text_metrics(GdiFont *font);
539 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
541 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
542 'W','i','n','d','o','w','s',' ','N','T','\\',
543 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
544 'S','y','s','t','e','m','L','i','n','k',0};
546 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
547 'F','o','n','t','L','i','n','k','\\',
548 'S','y','s','t','e','m','L','i','n','k',0};
550 /****************************************
551 * Notes on .fon files
553 * The fonts System, FixedSys and Terminal are special. There are typically multiple
554 * versions installed for different resolutions and codepages. Windows stores which one to use
555 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
557 * FIXEDFON.FON FixedSys
559 * OEMFONT.FON Terminal
560 * LogPixels Current dpi set by the display control panel applet
561 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
562 * also has a LogPixels value that appears to mirror this)
564 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
565 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
566 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
567 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
568 * so that makes sense.
570 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
571 * to be mapped into the registry on Windows 2000 at least).
574 * ega80woa.fon=ega80850.fon
575 * ega40woa.fon=ega40850.fon
576 * cga80woa.fon=cga80850.fon
577 * cga40woa.fon=cga40850.fon
580 /* These are all structures needed for the GSUB table */
582 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
583 #define TATEGAKI_LOWER_BOUND 0x02F1
599 GSUB_ScriptRecord ScriptRecord[1];
605 } GSUB_LangSysRecord;
610 GSUB_LangSysRecord LangSysRecord[1];
614 WORD LookupOrder; /* Reserved */
615 WORD ReqFeatureIndex;
617 WORD FeatureIndex[1];
623 } GSUB_FeatureRecord;
627 GSUB_FeatureRecord FeatureRecord[1];
631 WORD FeatureParams; /* Reserved */
633 WORD LookupListIndex[1];
652 } GSUB_CoverageFormat1;
657 WORD StartCoverageIndex;
663 GSUB_RangeRecord RangeRecord[1];
664 } GSUB_CoverageFormat2;
667 WORD SubstFormat; /* = 1 */
670 } GSUB_SingleSubstFormat1;
673 WORD SubstFormat; /* = 2 */
677 }GSUB_SingleSubstFormat2;
679 #ifdef HAVE_CARBON_CARBON_H
680 static char *find_cache_dir(void)
684 static char cached_path[MAX_PATH];
685 static const char *wine = "/Wine", *fonts = "/Fonts";
687 if(*cached_path) return cached_path;
689 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
692 WARN("can't create cached data folder\n");
695 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
698 WARN("can't create cached data path\n");
702 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
704 ERR("Could not create full path\n");
708 strcat(cached_path, wine);
710 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
712 WARN("Couldn't mkdir %s\n", cached_path);
716 strcat(cached_path, fonts);
717 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
719 WARN("Couldn't mkdir %s\n", cached_path);
726 /******************************************************************
729 * Extracts individual TrueType font files from a Mac suitcase font
730 * and saves them into the user's caches directory (see
732 * Returns a NULL terminated array of filenames.
734 * We do this because they are apps that try to read ttf files
735 * themselves and they don't like Mac suitcase files.
737 static char **expand_mac_font(const char *path)
744 const char *filename;
748 unsigned int size, max_size;
751 TRACE("path %s\n", path);
753 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
756 WARN("failed to get ref\n");
760 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
763 TRACE("no data fork, so trying resource fork\n");
764 res_ref = FSOpenResFile(&ref, fsRdPerm);
767 TRACE("unable to open resource fork\n");
774 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
777 CloseResFile(res_ref);
781 out_dir = find_cache_dir();
783 filename = strrchr(path, '/');
784 if(!filename) filename = path;
787 /* output filename has the form out_dir/filename_%04x.ttf */
788 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
795 unsigned short *num_faces_ptr, num_faces, face;
798 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
800 fond = Get1IndResource(fond_res, idx);
802 TRACE("got fond resource %d\n", idx);
805 fam_rec = *(FamRec**)fond;
806 num_faces_ptr = (unsigned short *)(fam_rec + 1);
807 num_faces = GET_BE_WORD(*num_faces_ptr);
809 assoc = (AsscEntry*)(num_faces_ptr + 1);
810 TRACE("num faces %04x\n", num_faces);
811 for(face = 0; face < num_faces; face++, assoc++)
814 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
815 unsigned short size, font_id;
818 size = GET_BE_WORD(assoc->fontSize);
819 font_id = GET_BE_WORD(assoc->fontID);
822 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
826 TRACE("trying to load sfnt id %04x\n", font_id);
827 sfnt = GetResource(sfnt_res, font_id);
830 TRACE("can't get sfnt resource %04x\n", font_id);
834 output = HeapAlloc(GetProcessHeap(), 0, output_len);
839 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
841 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
842 if(fd != -1 || errno == EEXIST)
846 unsigned char *sfnt_data;
849 sfnt_data = *(unsigned char**)sfnt;
850 write(fd, sfnt_data, GetHandleSize(sfnt));
854 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
857 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
859 ret.array[ret.size++] = output;
863 WARN("unable to create %s\n", output);
864 HeapFree(GetProcessHeap(), 0, output);
867 ReleaseResource(sfnt);
870 ReleaseResource(fond);
873 CloseResFile(res_ref);
878 #endif /* HAVE_CARBON_CARBON_H */
880 static inline BOOL is_win9x(void)
882 return GetVersion() & 0x80000000;
885 This function builds an FT_Fixed from a double. It fails if the absolute
886 value of the float number is greater than 32768.
888 static inline FT_Fixed FT_FixedFromFloat(double f)
894 This function builds an FT_Fixed from a FIXED. It simply put f.value
895 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
897 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
899 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
902 static BOOL is_hinting_enabled(void)
904 static int enabled = -1;
908 /* Use the >= 2.2.0 function if available */
909 if (pFT_Get_TrueType_Engine_Type)
911 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
912 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
914 #ifdef FT_DRIVER_HAS_HINTER
917 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
918 FT_Module mod = pFT_Get_Module(library, "truetype");
919 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
922 else enabled = FALSE;
923 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
928 static BOOL is_subpixel_rendering_enabled( void )
930 #ifdef HAVE_FREETYPE_FTLCDFIL_H
931 static int enabled = -1;
934 enabled = (pFT_Library_SetLcdFilter &&
935 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
936 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
945 static const struct list *get_face_list_from_family(const Family *family)
947 if (!list_empty(&family->faces))
948 return &family->faces;
950 return family->replacement;
953 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
959 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
961 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
963 const struct list *face_list;
964 if(face_name && strcmpiW(face_name, family->FamilyName))
966 face_list = get_face_list_from_family(family);
967 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
971 file = strrchrW(face->file, '/');
976 if(strcmpiW(file, file_name)) continue;
984 static Family *find_family_from_name(const WCHAR *name)
988 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
990 if(!strcmpiW(family->FamilyName, name))
997 static Family *find_family_from_any_name(const WCHAR *name)
1001 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1003 if(!strcmpiW(family->FamilyName, name))
1005 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1012 static void DumpSubstList(void)
1016 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1018 if(psub->from.charset != -1 || psub->to.charset != -1)
1019 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1020 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1022 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1023 debugstr_w(psub->to.name));
1028 static LPWSTR strdupW(LPCWSTR p)
1031 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1032 ret = HeapAlloc(GetProcessHeap(), 0, len);
1033 memcpy(ret, p, len);
1037 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1042 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1044 if(!strcmpiW(element->from.name, from_name) &&
1045 (element->from.charset == from_charset ||
1046 element->from.charset == -1))
1053 #define ADD_FONT_SUBST_FORCE 1
1055 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1057 FontSubst *from_exist, *to_exist;
1059 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1061 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1063 list_remove(&from_exist->entry);
1064 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1065 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1066 HeapFree(GetProcessHeap(), 0, from_exist);
1072 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1076 HeapFree(GetProcessHeap(), 0, subst->to.name);
1077 subst->to.name = strdupW(to_exist->to.name);
1080 list_add_tail(subst_list, &subst->entry);
1085 HeapFree(GetProcessHeap(), 0, subst->from.name);
1086 HeapFree(GetProcessHeap(), 0, subst->to.name);
1087 HeapFree(GetProcessHeap(), 0, subst);
1091 static WCHAR *towstr(UINT cp, const char *str)
1096 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1097 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1098 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1102 static char *strWtoA(UINT cp, const WCHAR *str)
1104 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1105 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1106 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1110 static void split_subst_info(NameCs *nc, LPSTR str)
1112 CHAR *p = strrchr(str, ',');
1116 nc->charset = strtol(p+1, NULL, 10);
1119 nc->name = towstr(CP_ACP, str);
1122 static void LoadSubstList(void)
1126 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1130 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1131 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1132 &hkey) == ERROR_SUCCESS) {
1134 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1135 &valuelen, &datalen, NULL, NULL);
1137 valuelen++; /* returned value doesn't include room for '\0' */
1138 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1139 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1143 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1144 &dlen) == ERROR_SUCCESS) {
1145 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1147 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1148 split_subst_info(&psub->from, value);
1149 split_subst_info(&psub->to, data);
1151 /* Win 2000 doesn't allow mapping between different charsets
1152 or mapping of DEFAULT_CHARSET */
1153 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1154 psub->to.charset == DEFAULT_CHARSET) {
1155 HeapFree(GetProcessHeap(), 0, psub->to.name);
1156 HeapFree(GetProcessHeap(), 0, psub->from.name);
1157 HeapFree(GetProcessHeap(), 0, psub);
1159 add_font_subst(&font_subst_list, psub, 0);
1161 /* reset dlen and vlen */
1165 HeapFree(GetProcessHeap(), 0, data);
1166 HeapFree(GetProcessHeap(), 0, value);
1172 /*****************************************************************
1173 * get_name_table_entry
1175 * Supply the platform, encoding, language and name ids in req
1176 * and if the name exists the function will fill in the string
1177 * and string_len members. The string is owned by FreeType so
1178 * don't free it. Returns TRUE if the name is found else FALSE.
1180 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1183 FT_UInt num_names, name_index;
1185 if(FT_IS_SFNT(ft_face))
1187 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1189 for(name_index = 0; name_index < num_names; name_index++)
1191 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1193 if((name.platform_id == req->platform_id) &&
1194 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1195 (name.language_id == req->language_id) &&
1196 (name.name_id == req->name_id))
1198 req->string = name.string;
1199 req->string_len = name.string_len;
1206 req->string_len = 0;
1210 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1215 name.platform_id = TT_PLATFORM_MICROSOFT;
1216 name.language_id = language_id;
1217 name.name_id = name_id;
1219 if(get_name_table_entry(ft_face, &name))
1223 /* String is not nul terminated and string_len is a byte length. */
1224 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1225 for(i = 0; i < name.string_len / 2; i++)
1227 WORD *tmp = (WORD *)&name.string[i * 2];
1228 ret[i] = GET_BE_WORD(*tmp);
1231 TRACE("Got localised name %s\n", debugstr_w(ret));
1237 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1239 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1240 if (f1->scalable) return TRUE;
1241 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1242 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1245 static void release_family( Family *family )
1247 if (--family->refcount) return;
1248 assert( list_empty( &family->faces ));
1249 list_remove( &family->entry );
1250 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1251 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1252 HeapFree( GetProcessHeap(), 0, family );
1255 static void release_face( Face *face )
1257 if (--face->refcount) return;
1260 list_remove( &face->entry );
1261 release_family( face->family );
1263 HeapFree( GetProcessHeap(), 0, face->file );
1264 HeapFree( GetProcessHeap(), 0, face->StyleName );
1265 HeapFree( GetProcessHeap(), 0, face->FullName );
1266 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1267 HeapFree( GetProcessHeap(), 0, face );
1270 static inline int style_order(const Face *face)
1272 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1280 case NTM_BOLD | NTM_ITALIC:
1283 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1284 debugstr_w(face->family->FamilyName),
1285 debugstr_w(face->StyleName),
1291 static BOOL insert_face_in_family_list( Face *face, Family *family )
1295 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1297 if (faces_equal( face, cursor ))
1299 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1300 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1301 cursor->font_version, face->font_version);
1303 if (face->font_version <= cursor->font_version)
1305 TRACE("Original font %s is newer so skipping %s\n",
1306 debugstr_w(cursor->file), debugstr_w(face->file));
1311 TRACE("Replacing original %s with %s\n",
1312 debugstr_w(cursor->file), debugstr_w(face->file));
1313 list_add_before( &cursor->entry, &face->entry );
1314 face->family = family;
1317 release_face( cursor );
1322 TRACE("Adding new %s\n", debugstr_w(face->file));
1324 if (style_order( face ) < style_order( cursor )) break;
1327 list_add_before( &cursor->entry, &face->entry );
1328 face->family = family;
1334 /****************************************************************
1335 * NB This function stores the ptrs to the strings to save copying.
1336 * Don't free them after calling.
1338 static Family *create_family( WCHAR *name, WCHAR *english_name )
1340 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1341 family->refcount = 1;
1342 family->FamilyName = name;
1343 family->EnglishName = english_name;
1344 list_init( &family->faces );
1345 family->replacement = &family->faces;
1346 list_add_tail( &font_list, &family->entry );
1351 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1353 DWORD type, size = sizeof(DWORD);
1355 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1356 type != REG_DWORD || size != sizeof(DWORD))
1359 return ERROR_BAD_CONFIGURATION;
1361 return ERROR_SUCCESS;
1364 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1366 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1369 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1371 DWORD needed, strike_index = 0;
1374 /* If we have a File Name key then this is a real font, not just the parent
1375 key of a bunch of non-scalable strikes */
1376 needed = buffer_size;
1377 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1380 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1381 face->cached_enum_data = NULL;
1382 face->family = NULL;
1385 face->file = strdupW( buffer );
1386 face->StyleName = strdupW(face_name);
1388 needed = buffer_size;
1389 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1390 face->FullName = strdupW( buffer );
1392 face->FullName = NULL;
1394 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1395 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1396 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1397 reg_load_dword(hkey_face, face_flags_value, (DWORD*)&face->flags);
1399 needed = sizeof(face->fs);
1400 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1402 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1404 face->scalable = TRUE;
1405 memset(&face->size, 0, sizeof(face->size));
1409 face->scalable = FALSE;
1410 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1411 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1412 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1413 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1414 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1416 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1417 face->size.height, face->size.width, face->size.size >> 6,
1418 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1421 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1422 face->fs.fsCsb[0], face->fs.fsCsb[1],
1423 face->fs.fsUsb[0], face->fs.fsUsb[1],
1424 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1426 if (insert_face_in_family_list(face, family))
1427 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1429 release_face( face );
1432 /* load bitmap strikes */
1434 needed = buffer_size;
1435 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1437 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1439 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1440 RegCloseKey(hkey_strike);
1442 needed = buffer_size;
1446 static void load_font_list_from_cache(HKEY hkey_font_cache)
1448 DWORD size, family_index = 0;
1453 size = sizeof(buffer);
1454 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1456 WCHAR *english_family = NULL;
1457 WCHAR *family_name = strdupW( buffer );
1458 DWORD face_index = 0;
1460 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1461 TRACE("opened family key %s\n", debugstr_w(family_name));
1462 size = sizeof(buffer);
1463 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1464 english_family = strdupW( buffer );
1466 family = create_family(family_name, english_family);
1470 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1471 subst->from.name = strdupW(english_family);
1472 subst->from.charset = -1;
1473 subst->to.name = strdupW(family_name);
1474 subst->to.charset = -1;
1475 add_font_subst(&font_subst_list, subst, 0);
1478 size = sizeof(buffer);
1479 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1481 WCHAR *face_name = strdupW( buffer );
1484 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1486 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1487 RegCloseKey(hkey_face);
1489 HeapFree( GetProcessHeap(), 0, face_name );
1490 size = sizeof(buffer);
1492 RegCloseKey(hkey_family);
1493 release_family( family );
1494 size = sizeof(buffer);
1498 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1501 HKEY hkey_wine_fonts;
1503 /* We don't want to create the fonts key as volatile, so open this first */
1504 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1505 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1506 if(ret != ERROR_SUCCESS)
1508 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1512 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1513 KEY_ALL_ACCESS, NULL, hkey, disposition);
1514 RegCloseKey(hkey_wine_fonts);
1518 static void add_face_to_cache(Face *face)
1520 HKEY hkey_family, hkey_face;
1521 WCHAR *face_key_name;
1523 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1524 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1525 if(face->family->EnglishName)
1526 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1527 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1530 face_key_name = face->StyleName;
1533 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1534 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1535 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1537 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1540 HeapFree(GetProcessHeap(), 0, face_key_name);
1542 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1543 (strlenW(face->file) + 1) * sizeof(WCHAR));
1545 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1546 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1548 reg_save_dword(hkey_face, face_index_value, face->face_index);
1549 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1550 reg_save_dword(hkey_face, face_version_value, face->font_version);
1551 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1553 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1557 reg_save_dword(hkey_face, face_height_value, face->size.height);
1558 reg_save_dword(hkey_face, face_width_value, face->size.width);
1559 reg_save_dword(hkey_face, face_size_value, face->size.size);
1560 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1561 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1562 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1564 RegCloseKey(hkey_face);
1565 RegCloseKey(hkey_family);
1568 static WCHAR *prepend_at(WCHAR *family)
1575 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1577 strcpyW(str + 1, family);
1578 HeapFree(GetProcessHeap(), 0, family);
1582 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1584 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1585 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1587 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1593 else if (!strcmpiW( *name, *english ))
1595 HeapFree( GetProcessHeap(), 0, *english );
1601 *name = prepend_at( *name );
1602 *english = prepend_at( *english );
1606 static Family *get_family( FT_Face ft_face, BOOL vertical )
1609 WCHAR *name, *english_name;
1611 get_family_names( ft_face, &name, &english_name, vertical );
1613 family = find_family_from_name( name );
1617 family = create_family( name, english_name );
1620 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1621 subst->from.name = strdupW( english_name );
1622 subst->from.charset = -1;
1623 subst->to.name = strdupW( name );
1624 subst->to.charset = -1;
1625 add_font_subst( &font_subst_list, subst, 0 );
1630 HeapFree( GetProcessHeap(), 0, name );
1631 HeapFree( GetProcessHeap(), 0, english_name );
1638 static inline FT_Fixed get_font_version( FT_Face ft_face )
1640 FT_Fixed version = 0;
1643 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1644 if (header) version = header->Font_Revision;
1649 static inline DWORD get_ntm_flags( FT_Face ft_face )
1652 FT_ULong table_size = 0;
1654 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1655 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1656 if (flags == 0) flags = NTM_REGULAR;
1658 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1659 flags |= NTM_PS_OPENTYPE;
1664 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1666 int internal_leading = 0;
1667 FT_WinFNT_HeaderRec winfnt_header;
1669 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1670 internal_leading = winfnt_header.internal_leading;
1672 return internal_leading;
1675 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1680 FT_WinFNT_HeaderRec winfnt_header;
1683 memset( fs, 0, sizeof(*fs) );
1685 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1688 fs->fsUsb[0] = os2->ulUnicodeRange1;
1689 fs->fsUsb[1] = os2->ulUnicodeRange2;
1690 fs->fsUsb[2] = os2->ulUnicodeRange3;
1691 fs->fsUsb[3] = os2->ulUnicodeRange4;
1693 if (os2->version == 0)
1695 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1696 fs->fsCsb[0] = FS_LATIN1;
1698 fs->fsCsb[0] = FS_SYMBOL;
1702 fs->fsCsb[0] = os2->ulCodePageRange1;
1703 fs->fsCsb[1] = os2->ulCodePageRange2;
1708 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1710 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1711 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1712 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1717 if (fs->fsCsb[0] == 0)
1719 /* let's see if we can find any interesting cmaps */
1720 for (i = 0; i < ft_face->num_charmaps; i++)
1722 switch (ft_face->charmaps[i]->encoding)
1724 case FT_ENCODING_UNICODE:
1725 case FT_ENCODING_APPLE_ROMAN:
1726 fs->fsCsb[0] |= FS_LATIN1;
1728 case FT_ENCODING_MS_SYMBOL:
1729 fs->fsCsb[0] |= FS_SYMBOL;
1738 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1741 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1742 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1745 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1746 if (!face->StyleName)
1747 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1748 if (!face->StyleName)
1750 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1753 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1754 if (!face->FullName)
1755 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1756 if (flags & ADDFONT_VERTICAL_FONT)
1757 face->FullName = prepend_at( face->FullName );
1761 face->file = towstr( CP_UNIXCP, file );
1762 face->font_data_ptr = NULL;
1763 face->font_data_size = 0;
1768 face->font_data_ptr = font_data_ptr;
1769 face->font_data_size = font_data_size;
1772 face->face_index = face_index;
1773 get_fontsig( ft_face, &face->fs );
1774 face->ntmFlags = get_ntm_flags( ft_face );
1775 face->font_version = get_font_version( ft_face );
1777 if (FT_IS_SCALABLE( ft_face ))
1779 memset( &face->size, 0, sizeof(face->size) );
1780 face->scalable = TRUE;
1784 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1785 size->height, size->width, size->size >> 6,
1786 size->x_ppem >> 6, size->y_ppem >> 6);
1787 face->size.height = size->height;
1788 face->size.width = size->width;
1789 face->size.size = size->size;
1790 face->size.x_ppem = size->x_ppem;
1791 face->size.y_ppem = size->y_ppem;
1792 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1793 face->scalable = FALSE;
1796 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1797 face->flags = flags;
1798 face->family = NULL;
1799 face->cached_enum_data = NULL;
1801 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1802 face->fs.fsCsb[0], face->fs.fsCsb[1],
1803 face->fs.fsUsb[0], face->fs.fsUsb[1],
1804 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1809 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1810 FT_Long face_index, DWORD flags )
1815 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
1816 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
1817 if (insert_face_in_family_list( face, family ))
1819 if (flags & ADDFONT_ADD_TO_CACHE)
1820 add_face_to_cache( face );
1822 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1823 debugstr_w(face->StyleName));
1825 release_face( face );
1826 release_family( family );
1829 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1830 FT_Long face_index, BOOL allow_bitmap )
1838 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1839 err = pFT_New_Face(library, file, face_index, &ft_face);
1843 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1844 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1849 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1853 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1854 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1856 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1860 if (!FT_IS_SFNT( ft_face ))
1862 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1864 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1870 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1871 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1872 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1874 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1875 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1879 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1880 we don't want to load these. */
1881 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1885 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1887 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1893 if (!ft_face->family_name || !ft_face->style_name)
1895 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1901 pFT_Done_Face( ft_face );
1905 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1908 FT_Long face_index = 0, num_faces;
1911 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1912 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1914 #ifdef HAVE_CARBON_CARBON_H
1917 char **mac_list = expand_mac_font(file);
1920 BOOL had_one = FALSE;
1922 for(cursor = mac_list; *cursor; cursor++)
1925 AddFontToList(*cursor, NULL, 0, flags);
1926 HeapFree(GetProcessHeap(), 0, *cursor);
1928 HeapFree(GetProcessHeap(), 0, mac_list);
1933 #endif /* HAVE_CARBON_CARBON_H */
1936 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
1937 if (!ft_face) return 0;
1939 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1941 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1942 pFT_Done_Face(ft_face);
1946 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
1949 if (FT_HAS_VERTICAL(ft_face))
1951 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
1952 flags | ADDFONT_VERTICAL_FONT);
1956 num_faces = ft_face->num_faces;
1957 pFT_Done_Face(ft_face);
1958 } while(num_faces > ++face_index);
1962 static void DumpFontList(void)
1967 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
1968 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1969 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
1970 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1972 TRACE(" %d", face->size.height);
1979 /***********************************************************
1980 * The replacement list is a way to map an entire font
1981 * family onto another family. For example adding
1983 * [HKCU\Software\Wine\Fonts\Replacements]
1984 * "Wingdings"="Winedings"
1986 * would enumerate the Winedings font both as Winedings and
1987 * Wingdings. However if a real Wingdings font is present the
1988 * replacement does not take place.
1991 static void LoadReplaceList(void)
1994 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1998 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1999 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2001 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2002 &valuelen, &datalen, NULL, NULL);
2004 valuelen++; /* returned value doesn't include room for '\0' */
2005 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2006 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2010 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2011 &dlen) == ERROR_SUCCESS) {
2012 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2013 /* "NewName"="Oldname" */
2014 if(!find_family_from_any_name(value))
2016 Family * const family = find_family_from_any_name(data);
2019 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2020 if (new_family != NULL)
2022 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2023 new_family->FamilyName = strdupW(value);
2024 new_family->EnglishName = NULL;
2025 list_init(&new_family->faces);
2026 new_family->replacement = &family->faces;
2027 list_add_tail(&font_list, &new_family->entry);
2032 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2037 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2039 /* reset dlen and vlen */
2043 HeapFree(GetProcessHeap(), 0, data);
2044 HeapFree(GetProcessHeap(), 0, value);
2049 static const WCHAR *font_links_list[] =
2051 Lucida_Sans_Unicode,
2052 Microsoft_Sans_Serif,
2056 static const struct font_links_defaults_list
2058 /* Keyed off substitution for "MS Shell Dlg" */
2059 const WCHAR *shelldlg;
2060 /* Maximum of four substitutes, plus terminating NULL pointer */
2061 const WCHAR *substitutes[5];
2062 } font_links_defaults_list[] =
2064 /* Non East-Asian */
2065 { Tahoma, /* FIXME unverified ordering */
2066 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2068 /* Below lists are courtesy of
2069 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2073 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2075 /* Chinese Simplified */
2077 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2081 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2083 /* Chinese Traditional */
2085 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2090 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2092 SYSTEM_LINKS *font_link;
2094 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2096 if(!strcmpiW(font_link->font_name, name))
2103 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2114 SYSTEM_LINKS *font_link;
2116 psub = get_font_subst(&font_subst_list, name, -1);
2117 /* Don't store fonts that are only substitutes for other fonts */
2120 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2124 font_link = find_font_link(name);
2125 if (font_link == NULL)
2127 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2128 font_link->font_name = strdupW(name);
2129 list_init(&font_link->links);
2130 list_add_tail(&system_links, &font_link->entry);
2133 memset(&font_link->fs, 0, sizeof font_link->fs);
2134 for (i = 0; values[i] != NULL; i++)
2136 const struct list *face_list;
2137 CHILD_FONT *child_font;
2140 if (!strcmpiW(name,value))
2142 psub = get_font_subst(&font_subst_list, value, -1);
2144 value = psub->to.name;
2145 family = find_family_from_name(value);
2149 /* Use first extant filename for this Family */
2150 face_list = get_face_list_from_family(family);
2151 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2155 file = strrchrW(face->file, '/');
2164 face = find_face_from_filename(file, value);
2167 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2171 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2172 child_font->face = face;
2173 child_font->font = NULL;
2174 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2175 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2176 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2177 child_font->face->face_index);
2178 list_add_tail(&font_link->links, &child_font->entry);
2180 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2186 /*************************************************************
2189 static BOOL init_system_links(void)
2193 DWORD type, max_val, max_data, val_len, data_len, index;
2194 WCHAR *value, *data;
2195 WCHAR *entry, *next;
2196 SYSTEM_LINKS *font_link, *system_font_link;
2197 CHILD_FONT *child_font;
2198 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2199 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2200 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2205 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2207 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2208 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2209 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2210 val_len = max_val + 1;
2211 data_len = max_data;
2213 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2215 psub = get_font_subst(&font_subst_list, value, -1);
2216 /* Don't store fonts that are only substitutes for other fonts */
2219 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2222 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2223 font_link->font_name = strdupW(value);
2224 memset(&font_link->fs, 0, sizeof font_link->fs);
2225 list_init(&font_link->links);
2226 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2229 CHILD_FONT *child_font;
2231 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2233 next = entry + strlenW(entry) + 1;
2235 face_name = strchrW(entry, ',');
2239 while(isspaceW(*face_name))
2242 psub = get_font_subst(&font_subst_list, face_name, -1);
2244 face_name = psub->to.name;
2246 face = find_face_from_filename(entry, face_name);
2249 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2253 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2254 child_font->face = face;
2255 child_font->font = NULL;
2256 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2257 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2258 TRACE("Adding file %s index %ld\n",
2259 debugstr_w(child_font->face->file), child_font->face->face_index);
2260 list_add_tail(&font_link->links, &child_font->entry);
2262 list_add_tail(&system_links, &font_link->entry);
2264 val_len = max_val + 1;
2265 data_len = max_data;
2268 HeapFree(GetProcessHeap(), 0, value);
2269 HeapFree(GetProcessHeap(), 0, data);
2274 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2276 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2280 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2282 const FontSubst *psub2;
2283 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2285 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2287 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2288 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2290 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2291 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2293 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2295 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2301 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2304 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2305 system_font_link->font_name = strdupW(System);
2306 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2307 list_init(&system_font_link->links);
2309 face = find_face_from_filename(tahoma_ttf, Tahoma);
2312 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2313 child_font->face = face;
2314 child_font->font = NULL;
2315 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2316 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2317 TRACE("Found Tahoma in %s index %ld\n",
2318 debugstr_w(child_font->face->file), child_font->face->face_index);
2319 list_add_tail(&system_font_link->links, &child_font->entry);
2321 font_link = find_font_link(Tahoma);
2322 if (font_link != NULL)
2324 CHILD_FONT *font_link_entry;
2325 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2327 CHILD_FONT *new_child;
2328 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2329 new_child->face = font_link_entry->face;
2330 new_child->font = NULL;
2331 new_child->face->refcount++;
2332 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2333 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2334 list_add_tail(&system_font_link->links, &new_child->entry);
2337 list_add_tail(&system_links, &system_font_link->entry);
2341 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2344 struct dirent *dent;
2345 char path[MAX_PATH];
2347 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2349 dir = opendir(dirname);
2351 WARN("Can't open directory %s\n", debugstr_a(dirname));
2354 while((dent = readdir(dir)) != NULL) {
2355 struct stat statbuf;
2357 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2360 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2362 sprintf(path, "%s/%s", dirname, dent->d_name);
2364 if(stat(path, &statbuf) == -1)
2366 WARN("Can't stat %s\n", debugstr_a(path));
2369 if(S_ISDIR(statbuf.st_mode))
2370 ReadFontDir(path, external_fonts);
2373 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2374 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2375 AddFontToList(path, NULL, 0, addfont_flags);
2382 #ifdef SONAME_LIBFONTCONFIG
2384 static BOOL fontconfig_enabled;
2386 static UINT parse_aa_pattern( FcPattern *pattern )
2392 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2393 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2395 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2399 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2400 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2401 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2402 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2403 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2409 static void init_fontconfig(void)
2411 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2415 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2419 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2420 LOAD_FUNCPTR(FcConfigSubstitute);
2421 LOAD_FUNCPTR(FcFontList);
2422 LOAD_FUNCPTR(FcFontSetDestroy);
2423 LOAD_FUNCPTR(FcInit);
2424 LOAD_FUNCPTR(FcObjectSetAdd);
2425 LOAD_FUNCPTR(FcObjectSetCreate);
2426 LOAD_FUNCPTR(FcObjectSetDestroy);
2427 LOAD_FUNCPTR(FcPatternCreate);
2428 LOAD_FUNCPTR(FcPatternDestroy);
2429 LOAD_FUNCPTR(FcPatternGetBool);
2430 LOAD_FUNCPTR(FcPatternGetInteger);
2431 LOAD_FUNCPTR(FcPatternGetString);
2436 FcPattern *pattern = pFcPatternCreate();
2437 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2438 default_aa_flags = parse_aa_pattern( pattern );
2439 pFcPatternDestroy( pattern );
2440 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2441 fontconfig_enabled = TRUE;
2445 static void load_fontconfig_fonts(void)
2454 if (!fontconfig_enabled) return;
2456 pat = pFcPatternCreate();
2457 os = pFcObjectSetCreate();
2458 pFcObjectSetAdd(os, FC_FILE);
2459 pFcObjectSetAdd(os, FC_SCALABLE);
2460 pFcObjectSetAdd(os, FC_ANTIALIAS);
2461 pFcObjectSetAdd(os, FC_RGBA);
2462 fontset = pFcFontList(NULL, pat, os);
2463 if(!fontset) return;
2464 for(i = 0; i < fontset->nfont; i++) {
2468 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2471 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2473 /* We're just interested in OT/TT fonts for now, so this hack just
2474 picks up the scalable fonts without extensions .pf[ab] to save time
2475 loading every other font */
2477 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2479 TRACE("not scalable\n");
2483 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2484 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2486 len = strlen( file );
2487 if(len < 4) continue;
2488 ext = &file[ len - 3 ];
2489 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2490 AddFontToList(file, NULL, 0,
2491 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2493 pFcFontSetDestroy(fontset);
2494 pFcObjectSetDestroy(os);
2495 pFcPatternDestroy(pat);
2498 #elif defined(HAVE_CARBON_CARBON_H)
2500 static void load_mac_font_callback(const void *value, void *context)
2502 CFStringRef pathStr = value;
2506 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2507 path = HeapAlloc(GetProcessHeap(), 0, len);
2508 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2510 TRACE("font file %s\n", path);
2511 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2513 HeapFree(GetProcessHeap(), 0, path);
2516 static void load_mac_fonts(void)
2518 CFStringRef removeDupesKey;
2519 CFBooleanRef removeDupesValue;
2520 CFDictionaryRef options;
2521 CTFontCollectionRef col;
2523 CFMutableSetRef paths;
2526 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2527 removeDupesValue = kCFBooleanTrue;
2528 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2529 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2530 col = CTFontCollectionCreateFromAvailableFonts(options);
2531 if (options) CFRelease(options);
2534 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2538 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2542 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2546 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2549 WARN("CFSetCreateMutable failed\n");
2554 for (i = 0; i < CFArrayGetCount(descs); i++)
2556 CTFontDescriptorRef desc;
2565 desc = CFArrayGetValueAtIndex(descs, i);
2567 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2568 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2569 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2570 if (!font) continue;
2572 atsFont = CTFontGetPlatformFont(font, NULL);
2579 status = ATSFontGetFileReference(atsFont, &fsref);
2581 if (status != noErr) continue;
2583 url = CFURLCreateFromFSRef(NULL, &fsref);
2586 ext = CFURLCopyPathExtension(url);
2589 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2590 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2599 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2601 if (!path) continue;
2603 CFSetAddValue(paths, path);
2609 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2615 static char *get_data_dir_path( LPCWSTR file )
2617 char *unix_name = NULL;
2618 const char *data_dir = wine_get_data_dir();
2620 if (!data_dir) data_dir = wine_get_build_dir();
2624 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2626 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2627 strcpy(unix_name, data_dir);
2628 strcat(unix_name, "/fonts/");
2630 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2635 static BOOL load_font_from_data_dir(LPCWSTR file)
2638 char *unix_name = get_data_dir_path( file );
2642 EnterCriticalSection( &freetype_cs );
2643 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2644 LeaveCriticalSection( &freetype_cs );
2645 HeapFree(GetProcessHeap(), 0, unix_name);
2650 static char *get_winfonts_dir_path(LPCWSTR file)
2652 static const WCHAR slashW[] = {'\\','\0'};
2653 WCHAR windowsdir[MAX_PATH];
2655 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2656 strcatW(windowsdir, fontsW);
2657 strcatW(windowsdir, slashW);
2658 strcatW(windowsdir, file);
2659 return wine_get_unix_file_name( windowsdir );
2662 static void load_system_fonts(void)
2665 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2666 const WCHAR * const *value;
2668 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2671 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2672 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2673 strcatW(windowsdir, fontsW);
2674 for(value = SystemFontValues; *value; value++) {
2675 dlen = sizeof(data);
2676 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2680 sprintfW(pathW, fmtW, windowsdir, data);
2681 if((unixname = wine_get_unix_file_name(pathW))) {
2682 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2683 HeapFree(GetProcessHeap(), 0, unixname);
2686 load_font_from_data_dir(data);
2693 /*************************************************************
2695 * This adds registry entries for any externally loaded fonts
2696 * (fonts from fontconfig or FontDirs). It also deletes entries
2697 * of no longer existing fonts.
2700 static void update_reg_entries(void)
2702 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2708 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2710 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2711 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2712 ERR("Can't create Windows font reg key\n");
2716 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2717 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2718 ERR("Can't create Windows font reg key\n");
2722 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2723 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2724 ERR("Can't create external font reg key\n");
2728 /* enumerate the fonts and add external ones to the two keys */
2730 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2731 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2733 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
2737 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2738 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2739 strcpyW(valueW, face->FullName);
2743 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2744 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2745 strcpyW(valueW, family->FamilyName);
2748 buffer = strWtoA( CP_UNIXCP, face->file );
2749 path = wine_get_dos_file_name( buffer );
2750 HeapFree( GetProcessHeap(), 0, buffer );
2754 else if ((file = strrchrW(face->file, '/')))
2759 len = strlenW(file) + 1;
2760 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2761 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2762 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2764 HeapFree(GetProcessHeap(), 0, path);
2765 HeapFree(GetProcessHeap(), 0, valueW);
2769 if(external_key) RegCloseKey(external_key);
2770 if(win9x_key) RegCloseKey(win9x_key);
2771 if(winnt_key) RegCloseKey(winnt_key);
2775 static void delete_external_font_keys(void)
2777 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2778 DWORD dlen, vlen, datalen, valuelen, i, type;
2782 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2783 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2784 ERR("Can't create Windows font reg key\n");
2788 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2789 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2790 ERR("Can't create Windows font reg key\n");
2794 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2795 ERR("Can't create external font reg key\n");
2799 /* Delete all external fonts added last time */
2801 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2802 &valuelen, &datalen, NULL, NULL);
2803 valuelen++; /* returned value doesn't include room for '\0' */
2804 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2805 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2807 dlen = datalen * sizeof(WCHAR);
2810 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2811 &dlen) == ERROR_SUCCESS) {
2813 RegDeleteValueW(winnt_key, valueW);
2814 RegDeleteValueW(win9x_key, valueW);
2815 /* reset dlen and vlen */
2819 HeapFree(GetProcessHeap(), 0, data);
2820 HeapFree(GetProcessHeap(), 0, valueW);
2822 /* Delete the old external fonts key */
2823 RegCloseKey(external_key);
2824 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2827 if(win9x_key) RegCloseKey(win9x_key);
2828 if(winnt_key) RegCloseKey(winnt_key);
2831 /*************************************************************
2832 * WineEngAddFontResourceEx
2835 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2841 if (ft_handle) /* do it only if we have freetype up and running */
2845 EnterCriticalSection( &freetype_cs );
2847 if((unixname = wine_get_unix_file_name(file)))
2849 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2851 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2852 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2853 HeapFree(GetProcessHeap(), 0, unixname);
2855 if (!ret && !strchrW(file, '\\')) {
2856 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2857 if ((unixname = get_winfonts_dir_path( file )))
2859 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2860 HeapFree(GetProcessHeap(), 0, unixname);
2862 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2863 if (!ret && (unixname = get_data_dir_path( file )))
2865 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2866 HeapFree(GetProcessHeap(), 0, unixname);
2870 LeaveCriticalSection( &freetype_cs );
2875 /*************************************************************
2876 * WineEngAddFontMemResourceEx
2879 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2883 if (ft_handle) /* do it only if we have freetype up and running */
2885 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2887 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2888 memcpy(pFontCopy, pbFont, cbFont);
2890 EnterCriticalSection( &freetype_cs );
2891 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2892 LeaveCriticalSection( &freetype_cs );
2896 TRACE("AddFontToList failed\n");
2897 HeapFree(GetProcessHeap(), 0, pFontCopy);
2900 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2901 * For now return something unique but quite random
2903 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2904 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2911 /*************************************************************
2912 * WineEngRemoveFontResourceEx
2915 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2918 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2922 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2928 if (!font_file) return NULL;
2930 file_len = strlenW( font_file );
2932 if (font_path && font_path[0])
2934 int path_len = strlenW( font_path );
2935 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2936 if (!fullname) return NULL;
2937 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2938 fullname[path_len] = '\\';
2939 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2943 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2944 if (!len) return NULL;
2945 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2946 if (!fullname) return NULL;
2947 GetFullPathNameW( font_file, len, fullname, NULL );
2950 unix_name = wine_get_unix_file_name( fullname );
2951 HeapFree( GetProcessHeap(), 0, fullname );
2955 #include <pshpack1.h>
2958 WORD num_of_resources;
2962 CHAR dfCopyright[60];
2968 WORD dfInternalLeading;
2969 WORD dfExternalLeading;
2977 BYTE dfPitchAndFamily;
2988 CHAR szFaceName[LF_FACESIZE];
2991 #include <poppack.h>
2993 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
2994 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2996 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2998 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3000 WCHAR *name, *english_name;
3002 NEWTEXTMETRICEXW ntm;
3005 if (!ft_face) return FALSE;
3006 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3007 get_family_names( ft_face, &name, &english_name, FALSE );
3008 pFT_Done_Face( ft_face );
3010 GetEnumStructs( face, name, &elf, &ntm, &type );
3011 release_face( face );
3012 HeapFree( GetProcessHeap(), 0, name );
3013 HeapFree( GetProcessHeap(), 0, english_name );
3015 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3017 memset( fd, 0, sizeof(*fd) );
3019 fd->num_of_resources = 1;
3021 fd->dfVersion = 0x200;
3022 fd->dfSize = sizeof(*fd);
3023 strcpy( fd->dfCopyright, "Wine fontdir" );
3024 fd->dfType = 0x4003; /* 0x0080 set if private */
3025 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3027 fd->dfHorizRes = 72;
3028 fd->dfAscent = ntm.ntmTm.tmAscent;
3029 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3030 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3031 fd->dfItalic = ntm.ntmTm.tmItalic;
3032 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3033 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3034 fd->dfWeight = ntm.ntmTm.tmWeight;
3035 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3037 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3038 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3039 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3040 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3041 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3042 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3043 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3044 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3045 fd->dfWidthBytes = 0;
3047 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3049 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3054 #define NE_FFLAGS_LIBMODULE 0x8000
3055 #define NE_OSFLAGS_WINDOWS 0x02
3057 static const char dos_string[0x40] = "This is a TrueType resource file";
3058 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3060 #include <pshpack2.h>
3081 struct ne_typeinfo fontdir_type;
3082 struct ne_nameinfo fontdir_name;
3083 struct ne_typeinfo scalable_type;
3084 struct ne_nameinfo scalable_name;
3086 BYTE fontdir_res_name[8];
3089 #include <poppack.h>
3091 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3095 DWORD size, written;
3097 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3098 char *font_fileA, *last_part, *ext;
3099 IMAGE_DOS_HEADER dos;
3100 IMAGE_OS2_HEADER ne =
3102 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3104 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3105 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3107 struct rsrc_tab rsrc_tab =
3111 { 0, 0, 0x0c50, 0x2c, 0 },
3113 { 0, 0, 0x0c50, 0x8001, 0 },
3115 { 7,'F','O','N','T','D','I','R'}
3118 memset( &dos, 0, sizeof(dos) );
3119 dos.e_magic = IMAGE_DOS_SIGNATURE;
3120 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3122 /* import name is last part\0, resident name is last part without extension
3123 non-resident name is "FONTRES:" + lfFaceName */
3125 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3126 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3127 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3129 last_part = strrchr( font_fileA, '\\' );
3130 if (last_part) last_part++;
3131 else last_part = font_fileA;
3132 import_name_len = strlen( last_part ) + 1;
3134 ext = strchr( last_part, '.' );
3135 if (ext) res_name_len = ext - last_part;
3136 else res_name_len = import_name_len - 1;
3138 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3140 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3141 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3142 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3143 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3145 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3147 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3148 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3149 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3150 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3152 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3153 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3157 HeapFree( GetProcessHeap(), 0, font_fileA );
3161 memcpy( ptr, &dos, sizeof(dos) );
3162 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3163 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3165 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3166 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3168 ptr = start + dos.e_lfanew + ne.ne_restab;
3169 *ptr++ = res_name_len;
3170 memcpy( ptr, last_part, res_name_len );
3172 ptr = start + dos.e_lfanew + ne.ne_imptab;
3173 *ptr++ = import_name_len;
3174 memcpy( ptr, last_part, import_name_len );
3176 ptr = start + ne.ne_nrestab;
3177 *ptr++ = non_res_name_len;
3178 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3179 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3181 ptr = start + (rsrc_tab.scalable_name.off << 4);
3182 memcpy( ptr, font_fileA, font_file_len );
3184 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3185 memcpy( ptr, fontdir, fontdir->dfSize );
3187 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3188 if (file != INVALID_HANDLE_VALUE)
3190 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3192 CloseHandle( file );
3195 HeapFree( GetProcessHeap(), 0, start );
3196 HeapFree( GetProcessHeap(), 0, font_fileA );
3201 /*************************************************************
3202 * WineEngCreateScalableFontResource
3205 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3206 LPCWSTR font_file, LPCWSTR font_path )
3208 char *unix_name = get_ttf_file_name( font_file, font_path );
3209 struct fontdir fontdir;
3212 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3213 SetLastError( ERROR_INVALID_PARAMETER );
3216 if (hidden) fontdir.dfType |= 0x80;
3217 ret = create_fot( resource, font_file, &fontdir );
3220 HeapFree( GetProcessHeap(), 0, unix_name );
3224 static const struct nls_update_font_list
3226 UINT ansi_cp, oem_cp;
3227 const char *oem, *fixed, *system;
3228 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3229 /* these are for font substitutes */
3230 const char *shelldlg, *tmsrmn;
3231 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3235 const char *from, *to;
3236 } arial_0, courier_new_0, times_new_roman_0;
3237 } nls_update_font_list[] =
3239 /* Latin 1 (United States) */
3240 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3241 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3242 "Tahoma","Times New Roman",
3243 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3246 /* Latin 1 (Multilingual) */
3247 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3248 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3249 "Tahoma","Times New Roman", /* FIXME unverified */
3250 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3253 /* Eastern Europe */
3254 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3255 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3256 "Tahoma","Times New Roman", /* FIXME unverified */
3257 "Fixedsys,238", "System,238",
3258 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3259 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3260 { "Arial CE,0", "Arial,238" },
3261 { "Courier New CE,0", "Courier New,238" },
3262 { "Times New Roman CE,0", "Times New Roman,238" }
3265 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3266 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3267 "Tahoma","Times New Roman", /* FIXME unverified */
3268 "Fixedsys,204", "System,204",
3269 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3270 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3271 { "Arial Cyr,0", "Arial,204" },
3272 { "Courier New Cyr,0", "Courier New,204" },
3273 { "Times New Roman Cyr,0", "Times New Roman,204" }
3276 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3277 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3278 "Tahoma","Times New Roman", /* FIXME unverified */
3279 "Fixedsys,161", "System,161",
3280 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3281 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3282 { "Arial Greek,0", "Arial,161" },
3283 { "Courier New Greek,0", "Courier New,161" },
3284 { "Times New Roman Greek,0", "Times New Roman,161" }
3287 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3288 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3289 "Tahoma","Times New Roman", /* FIXME unverified */
3290 "Fixedsys,162", "System,162",
3291 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3292 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3293 { "Arial Tur,0", "Arial,162" },
3294 { "Courier New Tur,0", "Courier New,162" },
3295 { "Times New Roman Tur,0", "Times New Roman,162" }
3298 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3299 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3300 "Tahoma","Times New Roman", /* FIXME unverified */
3301 "Fixedsys,177", "System,177",
3302 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3303 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3307 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3308 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3309 "Tahoma","Times New Roman", /* FIXME unverified */
3310 "Fixedsys,178", "System,178",
3311 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3312 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3316 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3317 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3318 "Tahoma","Times New Roman", /* FIXME unverified */
3319 "Fixedsys,186", "System,186",
3320 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3321 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3322 { "Arial Baltic,0", "Arial,186" },
3323 { "Courier New Baltic,0", "Courier New,186" },
3324 { "Times New Roman Baltic,0", "Times New Roman,186" }
3327 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3328 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3329 "Tahoma","Times New Roman", /* FIXME unverified */
3330 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3334 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3335 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3336 "Tahoma","Times New Roman", /* FIXME unverified */
3337 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3341 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3342 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3343 "MS UI Gothic","MS Serif",
3344 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3347 /* Chinese Simplified */
3348 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3349 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3350 "SimSun", "NSimSun",
3351 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3355 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3356 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3358 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3361 /* Chinese Traditional */
3362 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3363 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3364 "PMingLiU", "MingLiU",
3365 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3370 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3372 return ( ansi_cp == 932 /* CP932 for Japanese */
3373 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3374 || ansi_cp == 949 /* CP949 for Korean */
3375 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3378 static inline HKEY create_fonts_NT_registry_key(void)
3382 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3383 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3387 static inline HKEY create_fonts_9x_registry_key(void)
3391 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3392 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3396 static inline HKEY create_config_fonts_registry_key(void)
3400 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3401 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3405 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3407 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3409 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3410 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3411 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3412 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3415 static void set_value_key(HKEY hkey, const char *name, const char *value)
3418 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3420 RegDeleteValueA(hkey, name);
3423 static void update_font_info(void)
3425 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3426 char buf[40], cpbuf[40];
3429 UINT i, ansi_cp = 0, oem_cp = 0;
3430 DWORD screen_dpi = 96, font_dpi = 0;
3433 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3434 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3435 &hkey) == ERROR_SUCCESS)
3437 reg_load_dword(hkey, logpixels, &screen_dpi);
3441 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3444 reg_load_dword(hkey, logpixels, &font_dpi);
3446 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3447 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3448 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3449 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3450 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3452 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3453 if (is_dbcs_ansi_cp(ansi_cp))
3454 use_default_fallback = TRUE;
3457 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3459 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3464 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3465 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3467 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3468 ansi_cp, oem_cp, screen_dpi);
3470 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3471 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3474 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3478 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3479 nls_update_font_list[i].oem_cp == oem_cp)
3481 hkey = create_config_fonts_registry_key();
3482 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3483 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3484 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3487 hkey = create_fonts_NT_registry_key();
3488 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3491 hkey = create_fonts_9x_registry_key();
3492 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3495 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3497 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3498 strlen(nls_update_font_list[i].shelldlg)+1);
3499 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3500 strlen(nls_update_font_list[i].tmsrmn)+1);
3502 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3503 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3504 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3505 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3506 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3507 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3508 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3509 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3511 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3512 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3513 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3521 /* Delete the FontSubstitutes from other locales */
3522 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3524 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3525 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3526 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3532 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3535 static BOOL init_freetype(void)
3537 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3540 "Wine cannot find the FreeType font library. To enable Wine to\n"
3541 "use TrueType fonts please install a version of FreeType greater than\n"
3542 "or equal to 2.0.5.\n"
3543 "http://www.freetype.org\n");
3547 #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;}
3549 LOAD_FUNCPTR(FT_Done_Face)
3550 LOAD_FUNCPTR(FT_Get_Char_Index)
3551 LOAD_FUNCPTR(FT_Get_First_Char)
3552 LOAD_FUNCPTR(FT_Get_Module)
3553 LOAD_FUNCPTR(FT_Get_Next_Char)
3554 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3555 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3556 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3557 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3558 LOAD_FUNCPTR(FT_Init_FreeType)
3559 LOAD_FUNCPTR(FT_Library_Version)
3560 LOAD_FUNCPTR(FT_Load_Glyph)
3561 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3562 LOAD_FUNCPTR(FT_Matrix_Multiply)
3563 #ifndef FT_MULFIX_INLINED
3564 LOAD_FUNCPTR(FT_MulFix)
3566 LOAD_FUNCPTR(FT_New_Face)
3567 LOAD_FUNCPTR(FT_New_Memory_Face)
3568 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3569 LOAD_FUNCPTR(FT_Outline_Transform)
3570 LOAD_FUNCPTR(FT_Outline_Translate)
3571 LOAD_FUNCPTR(FT_Render_Glyph)
3572 LOAD_FUNCPTR(FT_Select_Charmap)
3573 LOAD_FUNCPTR(FT_Set_Charmap)
3574 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3575 LOAD_FUNCPTR(FT_Vector_Transform)
3576 LOAD_FUNCPTR(FT_Vector_Unit)
3578 /* Don't warn if these ones are missing */
3579 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3580 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3581 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3584 if(pFT_Init_FreeType(&library) != 0) {
3585 ERR("Can't init FreeType library\n");
3586 wine_dlclose(ft_handle, NULL, 0);
3590 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3592 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3593 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3594 ((FT_Version.minor << 8) & 0x00ff00) |
3595 ((FT_Version.patch ) & 0x0000ff);
3597 font_driver = &freetype_funcs;
3602 "Wine cannot find certain functions that it needs inside the FreeType\n"
3603 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3604 "FreeType to at least version 2.1.4.\n"
3605 "http://www.freetype.org\n");
3606 wine_dlclose(ft_handle, NULL, 0);
3611 static void init_font_list(void)
3613 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3614 static const WCHAR pathW[] = {'P','a','t','h',0};
3616 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3617 WCHAR windowsdir[MAX_PATH];
3619 const char *data_dir;
3621 #ifdef SONAME_LIBFONTCONFIG
3625 delete_external_font_keys();
3627 /* load the system bitmap fonts */
3628 load_system_fonts();
3630 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3631 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3632 strcatW(windowsdir, fontsW);
3633 if((unixname = wine_get_unix_file_name(windowsdir)))
3635 ReadFontDir(unixname, FALSE);
3636 HeapFree(GetProcessHeap(), 0, unixname);
3639 /* load the system truetype fonts */
3640 data_dir = wine_get_data_dir();
3641 if (!data_dir) data_dir = wine_get_build_dir();
3642 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3644 strcpy(unixname, data_dir);
3645 strcat(unixname, "/fonts/");
3646 ReadFontDir(unixname, TRUE);
3647 HeapFree(GetProcessHeap(), 0, unixname);
3650 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3651 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3652 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3654 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3655 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3656 &hkey) == ERROR_SUCCESS)
3658 LPWSTR data, valueW;
3659 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3660 &valuelen, &datalen, NULL, NULL);
3662 valuelen++; /* returned value doesn't include room for '\0' */
3663 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3664 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3667 dlen = datalen * sizeof(WCHAR);
3669 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3670 &dlen) == ERROR_SUCCESS)
3672 if(data[0] && (data[1] == ':'))
3674 if((unixname = wine_get_unix_file_name(data)))
3676 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3677 HeapFree(GetProcessHeap(), 0, unixname);
3680 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3682 WCHAR pathW[MAX_PATH];
3683 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3686 sprintfW(pathW, fmtW, windowsdir, data);
3687 if((unixname = wine_get_unix_file_name(pathW)))
3689 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3690 HeapFree(GetProcessHeap(), 0, unixname);
3693 load_font_from_data_dir(data);
3695 /* reset dlen and vlen */
3700 HeapFree(GetProcessHeap(), 0, data);
3701 HeapFree(GetProcessHeap(), 0, valueW);
3705 #ifdef SONAME_LIBFONTCONFIG
3706 load_fontconfig_fonts();
3707 #elif defined(HAVE_CARBON_CARBON_H)
3711 /* then look in any directories that we've specified in the config file */
3712 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3713 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3719 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3721 len += sizeof(WCHAR);
3722 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3723 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3725 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3726 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3727 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3728 TRACE( "got font path %s\n", debugstr_a(valueA) );
3733 LPSTR next = strchr( ptr, ':' );
3734 if (next) *next++ = 0;
3735 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3736 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3738 strcpy( unixname, home );
3739 strcat( unixname, ptr + 1 );
3740 ReadFontDir( unixname, TRUE );
3741 HeapFree( GetProcessHeap(), 0, unixname );
3744 ReadFontDir( ptr, TRUE );
3747 HeapFree( GetProcessHeap(), 0, valueA );
3749 HeapFree( GetProcessHeap(), 0, valueW );
3755 static BOOL move_to_front(const WCHAR *name)
3757 Family *family, *cursor2;
3758 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3760 if(!strcmpiW(family->FamilyName, name))
3762 list_remove(&family->entry);
3763 list_add_head(&font_list, &family->entry);
3770 static BOOL set_default(const WCHAR **name_list)
3774 if (move_to_front(*name_list)) return TRUE;
3781 static void reorder_font_list(void)
3783 set_default( default_serif_list );
3784 set_default( default_fixed_list );
3785 set_default( default_sans_list );
3788 /*************************************************************
3791 * Initialize FreeType library and create a list of available faces
3793 BOOL WineEngInit(void)
3798 /* update locale dependent font info in registry */
3801 if(!init_freetype()) return FALSE;
3803 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3805 ERR("Failed to create font mutex\n");
3808 WaitForSingleObject(font_mutex, INFINITE);
3810 create_font_cache_key(&hkey_font_cache, &disposition);
3812 if(disposition == REG_CREATED_NEW_KEY)
3815 load_font_list_from_cache(hkey_font_cache);
3817 reorder_font_list();
3824 if(disposition == REG_CREATED_NEW_KEY)
3825 update_reg_entries();
3827 init_system_links();
3829 ReleaseMutex(font_mutex);
3834 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3837 TT_HoriHeader *pHori;
3841 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3842 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3844 if(height == 0) height = 16;
3846 /* Calc. height of EM square:
3848 * For +ve lfHeight we have
3849 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3850 * Re-arranging gives:
3851 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3853 * For -ve lfHeight we have
3855 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3856 * with il = winAscent + winDescent - units_per_em]
3861 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3862 ppem = MulDiv(ft_face->units_per_EM, height,
3863 pHori->Ascender - pHori->Descender);
3865 ppem = MulDiv(ft_face->units_per_EM, height,
3866 pOS2->usWinAscent + pOS2->usWinDescent);
3874 static struct font_mapping *map_font_file( const char *name )
3876 struct font_mapping *mapping;
3880 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3881 if (fstat( fd, &st ) == -1) goto error;
3883 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3885 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3887 mapping->refcount++;
3892 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3895 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3898 if (mapping->data == MAP_FAILED)
3900 HeapFree( GetProcessHeap(), 0, mapping );
3903 mapping->refcount = 1;
3904 mapping->dev = st.st_dev;
3905 mapping->ino = st.st_ino;
3906 mapping->size = st.st_size;
3907 list_add_tail( &mappings_list, &mapping->entry );
3915 static void unmap_font_file( struct font_mapping *mapping )
3917 if (!--mapping->refcount)
3919 list_remove( &mapping->entry );
3920 munmap( mapping->data, mapping->size );
3921 HeapFree( GetProcessHeap(), 0, mapping );
3925 static LONG load_VDMX(GdiFont*, LONG);
3927 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3934 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
3938 char *filename = strWtoA( CP_UNIXCP, face->file );
3939 font->mapping = map_font_file( filename );
3940 HeapFree( GetProcessHeap(), 0, filename );
3943 WARN("failed to map %s\n", debugstr_w(face->file));
3946 data_ptr = font->mapping->data;
3947 data_size = font->mapping->size;
3951 data_ptr = face->font_data_ptr;
3952 data_size = face->font_data_size;
3955 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3957 ERR("FT_New_Face rets %d\n", err);
3961 /* set it here, as load_VDMX needs it */
3962 font->ft_face = ft_face;
3964 if(FT_IS_SCALABLE(ft_face)) {
3965 /* load the VDMX table if we have one */
3966 font->ppem = load_VDMX(font, height);
3968 font->ppem = calc_ppem_for_height(ft_face, height);
3969 TRACE("height %d => ppem %d\n", height, font->ppem);
3971 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3972 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3974 font->ppem = height;
3975 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3976 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3982 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3984 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3985 a single face with the requested charset. The idea is to check if
3986 the selected font supports the current ANSI codepage, if it does
3987 return the corresponding charset, else return the first charset */
3990 int acp = GetACP(), i;
3994 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3996 const SYSTEM_LINKS *font_link;
3998 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3999 return csi.ciCharset;
4001 font_link = find_font_link(family_name);
4002 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4003 return csi.ciCharset;
4006 for(i = 0; i < 32; i++) {
4008 if(face->fs.fsCsb[0] & fs0) {
4009 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4011 return csi.ciCharset;
4014 FIXME("TCI failing on %x\n", fs0);
4018 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4019 face->fs.fsCsb[0], debugstr_w(face->file));
4021 return DEFAULT_CHARSET;
4024 static GdiFont *alloc_font(void)
4026 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4029 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4030 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4032 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4033 ret->total_kern_pairs = (DWORD)-1;
4034 ret->kern_pairs = NULL;
4035 list_init(&ret->child_fonts);
4039 static void free_font(GdiFont *font)
4041 CHILD_FONT *child, *child_next;
4044 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4046 list_remove(&child->entry);
4048 free_font(child->font);
4049 release_face( child->face );
4050 HeapFree(GetProcessHeap(), 0, child);
4053 if (font->ft_face) pFT_Done_Face(font->ft_face);
4054 if (font->mapping) unmap_font_file( font->mapping );
4055 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4056 HeapFree(GetProcessHeap(), 0, font->potm);
4057 HeapFree(GetProcessHeap(), 0, font->name);
4058 for (i = 0; i < font->gmsize; i++)
4059 HeapFree(GetProcessHeap(),0,font->gm[i]);
4060 HeapFree(GetProcessHeap(), 0, font->gm);
4061 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4062 HeapFree(GetProcessHeap(), 0, font);
4066 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4068 FT_Face ft_face = font->ft_face;
4072 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4079 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4081 /* make sure value of len is the value freetype says it needs */
4084 FT_ULong needed = 0;
4085 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4086 if( !err && needed < len) len = needed;
4088 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4091 TRACE("Can't find table %c%c%c%c\n",
4092 /* bytes were reversed */
4093 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4094 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4100 /*************************************************************
4103 * load the vdmx entry for the specified height
4106 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4107 ( ( (FT_ULong)_x4 << 24 ) | \
4108 ( (FT_ULong)_x3 << 16 ) | \
4109 ( (FT_ULong)_x2 << 8 ) | \
4112 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4127 static LONG load_VDMX(GdiFont *font, LONG height)
4131 BYTE devXRatio, devYRatio;
4132 USHORT numRecs, numRatios;
4133 DWORD result, offset = -1;
4137 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4139 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4142 /* FIXME: need the real device aspect ratio */
4146 numRecs = GET_BE_WORD(hdr[1]);
4147 numRatios = GET_BE_WORD(hdr[2]);
4149 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4150 for(i = 0; i < numRatios; i++) {
4153 offset = (3 * 2) + (i * sizeof(Ratios));
4154 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4157 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4159 if((ratio.xRatio == 0 &&
4160 ratio.yStartRatio == 0 &&
4161 ratio.yEndRatio == 0) ||
4162 (devXRatio == ratio.xRatio &&
4163 devYRatio >= ratio.yStartRatio &&
4164 devYRatio <= ratio.yEndRatio))
4166 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4167 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4168 offset = GET_BE_WORD(tmp);
4174 FIXME("No suitable ratio found\n");
4178 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4180 BYTE startsz, endsz;
4183 recs = GET_BE_WORD(group.recs);
4184 startsz = group.startsz;
4185 endsz = group.endsz;
4187 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4189 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4190 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4191 if(result == GDI_ERROR) {
4192 FIXME("Failed to retrieve vTable\n");
4197 for(i = 0; i < recs; i++) {
4198 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4199 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4200 ppem = GET_BE_WORD(vTable[i * 3]);
4202 if(yMax + -yMin == height) {
4205 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4208 if(yMax + -yMin > height) {
4211 goto end; /* failed */
4213 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4214 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4215 ppem = GET_BE_WORD(vTable[i * 3]);
4216 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4222 TRACE("ppem not found for height %d\n", height);
4226 HeapFree(GetProcessHeap(), 0, vTable);
4232 static void dump_gdi_font_list(void)
4236 TRACE("---------- Font Cache ----------\n");
4237 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4238 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4239 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4242 static void grab_font( GdiFont *font )
4244 if (!font->refcount++)
4246 list_remove( &font->unused_entry );
4247 unused_font_count--;
4251 static void release_font( GdiFont *font )
4254 if (!--font->refcount)
4256 TRACE( "font %p\n", font );
4258 /* add it to the unused list */
4259 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4260 if (unused_font_count > UNUSED_CACHE_SIZE)
4262 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4263 TRACE( "freeing %p\n", font );
4264 list_remove( &font->entry );
4265 list_remove( &font->unused_entry );
4268 else unused_font_count++;
4270 if (TRACE_ON(font)) dump_gdi_font_list();
4274 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4276 if(font->font_desc.hash != fd->hash) return TRUE;
4277 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4278 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4279 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4280 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4283 static void calc_hash(FONT_DESC *pfd)
4285 DWORD hash = 0, *ptr, two_chars;
4289 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4291 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4293 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4295 pwc = (WCHAR *)&two_chars;
4297 *pwc = toupperW(*pwc);
4299 *pwc = toupperW(*pwc);
4303 hash ^= !pfd->can_use_bitmap;
4308 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4315 fd.can_use_bitmap = can_use_bitmap;
4318 /* try the in-use list */
4319 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4321 if(fontcmp(ret, &fd)) continue;
4322 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4323 list_remove( &ret->entry );
4324 list_add_head( &gdi_font_list, &ret->entry );
4331 static void add_to_cache(GdiFont *font)
4333 static DWORD cache_num = 1;
4335 font->cache_num = cache_num++;
4336 list_add_head(&gdi_font_list, &font->entry);
4337 TRACE( "font %p\n", font );
4340 /*************************************************************
4341 * create_child_font_list
4343 static BOOL create_child_font_list(GdiFont *font)
4346 SYSTEM_LINKS *font_link;
4347 CHILD_FONT *font_link_entry, *new_child;
4351 psub = get_font_subst(&font_subst_list, font->name, -1);
4352 font_name = psub ? psub->to.name : font->name;
4353 font_link = find_font_link(font_name);
4354 if (font_link != NULL)
4356 TRACE("found entry in system list\n");
4357 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4359 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4360 new_child->face = font_link_entry->face;
4361 new_child->font = NULL;
4362 new_child->face->refcount++;
4363 list_add_tail(&font->child_fonts, &new_child->entry);
4364 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4369 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4370 * Sans Serif. This is how asian windows get default fallbacks for fonts
4372 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4373 font->charset != OEM_CHARSET &&
4374 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4376 font_link = find_font_link(szDefaultFallbackLink);
4377 if (font_link != NULL)
4379 TRACE("found entry in default fallback list\n");
4380 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4382 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4383 new_child->face = font_link_entry->face;
4384 new_child->font = NULL;
4385 new_child->face->refcount++;
4386 list_add_tail(&font->child_fonts, &new_child->entry);
4387 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4396 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4398 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4400 if (pFT_Set_Charmap)
4403 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4405 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4407 for (i = 0; i < ft_face->num_charmaps; i++)
4409 if (ft_face->charmaps[i]->encoding == encoding)
4411 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4412 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4414 switch (ft_face->charmaps[i]->platform_id)
4417 cmap_def = ft_face->charmaps[i];
4419 case 0: /* Apple Unicode */
4420 cmap0 = ft_face->charmaps[i];
4422 case 1: /* Macintosh */
4423 cmap1 = ft_face->charmaps[i];
4426 cmap2 = ft_face->charmaps[i];
4428 case 3: /* Microsoft */
4429 cmap3 = ft_face->charmaps[i];
4434 if (cmap3) /* prefer Microsoft cmap table */
4435 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4437 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4439 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4441 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4443 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4445 return ft_err == FT_Err_Ok;
4448 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4452 /*************************************************************
4455 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4456 LPCWSTR output, const DEVMODEW *devmode )
4458 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4460 if (!physdev) return FALSE;
4461 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4466 /*************************************************************
4469 static BOOL freetype_DeleteDC( PHYSDEV dev )
4471 struct freetype_physdev *physdev = get_freetype_dev( dev );
4472 release_font( physdev->font );
4473 HeapFree( GetProcessHeap(), 0, physdev );
4477 static FT_Encoding pick_charmap( FT_Face face, int charset )
4479 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4480 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4481 const FT_Encoding *encs = regular_order;
4483 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4487 if (select_charmap( face, *encs )) break;
4493 #define GASP_GRIDFIT 0x01
4494 #define GASP_DOGRAY 0x02
4495 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4497 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4500 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4501 WORD *alloced = NULL, *ptr = buf;
4502 WORD num_recs, version;
4506 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4507 if (size == GDI_ERROR) return FALSE;
4508 if (size < 4 * sizeof(WORD)) return FALSE;
4509 if (size > sizeof(buf))
4511 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4512 if (!ptr) return FALSE;
4515 get_font_data( font, GASP_TAG, 0, ptr, size );
4517 version = GET_BE_WORD( *ptr++ );
4518 num_recs = GET_BE_WORD( *ptr++ );
4520 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4522 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4528 *flags = GET_BE_WORD( *(ptr + 1) );
4529 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4532 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4536 HeapFree( GetProcessHeap(), 0, alloced );
4540 /*************************************************************
4541 * freetype_SelectFont
4543 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4545 struct freetype_physdev *physdev = get_freetype_dev( dev );
4547 Face *face, *best, *best_bitmap;
4548 Family *family, *last_resort_family;
4549 const struct list *face_list;
4550 INT height, width = 0;
4551 unsigned int score = 0, new_score;
4552 signed int diff = 0, newdiff;
4553 BOOL bd, it, can_use_bitmap, want_vertical;
4557 FontSubst *psub = NULL;
4558 DC *dc = get_dc_ptr( dev->hdc );
4559 const SYSTEM_LINKS *font_link;
4561 if (!hfont) /* notification that the font has been changed by another driver */
4563 release_font( physdev->font );
4564 physdev->font = NULL;
4565 release_dc_ptr( dc );
4569 GetObjectW( hfont, sizeof(lf), &lf );
4570 lf.lfWidth = abs(lf.lfWidth);
4572 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4574 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4575 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4576 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4579 if(dc->GraphicsMode == GM_ADVANCED)
4581 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4582 /* Try to avoid not necessary glyph transformations */
4583 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4585 lf.lfHeight *= fabs(dcmat.eM11);
4586 lf.lfWidth *= fabs(dcmat.eM11);
4587 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4592 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4593 font scaling abilities. */
4594 dcmat.eM11 = dcmat.eM22 = 1.0;
4595 dcmat.eM21 = dcmat.eM12 = 0;
4596 lf.lfOrientation = lf.lfEscapement;
4597 if (dc->vport2WorldValid)
4599 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4600 lf.lfOrientation = -lf.lfOrientation;
4601 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4602 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4606 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4607 dcmat.eM21, dcmat.eM22);
4610 EnterCriticalSection( &freetype_cs );
4612 /* check the cache first */
4613 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4614 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4618 TRACE("not in cache\n");
4621 ret->font_desc.matrix = dcmat;
4622 ret->font_desc.lf = lf;
4623 ret->font_desc.can_use_bitmap = can_use_bitmap;
4624 calc_hash(&ret->font_desc);
4626 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4627 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4628 original value lfCharSet. Note this is a special case for
4629 Symbol and doesn't happen at least for "Wingdings*" */
4631 if(!strcmpiW(lf.lfFaceName, SymbolW))
4632 lf.lfCharSet = SYMBOL_CHARSET;
4634 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4635 switch(lf.lfCharSet) {
4636 case DEFAULT_CHARSET:
4637 csi.fs.fsCsb[0] = 0;
4640 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4641 csi.fs.fsCsb[0] = 0;
4647 if(lf.lfFaceName[0] != '\0') {
4648 CHILD_FONT *font_link_entry;
4649 LPWSTR FaceName = lf.lfFaceName;
4651 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4654 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4655 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4656 if (psub->to.charset != -1)
4657 lf.lfCharSet = psub->to.charset;
4660 /* We want a match on name and charset or just name if
4661 charset was DEFAULT_CHARSET. If the latter then
4662 we fixup the returned charset later in get_nearest_charset
4663 where we'll either use the charset of the current ansi codepage
4664 or if that's unavailable the first charset that the font supports.
4666 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4667 if (!strcmpiW(family->FamilyName, FaceName) ||
4668 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4670 font_link = find_font_link(family->FamilyName);
4671 face_list = get_face_list_from_family(family);
4672 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4673 if (!(face->scalable || can_use_bitmap))
4675 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4677 if (font_link != NULL &&
4678 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4680 if (!csi.fs.fsCsb[0])
4686 /* Search by full face name. */
4687 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4688 face_list = get_face_list_from_family(family);
4689 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4690 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4691 (face->scalable || can_use_bitmap))
4693 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4695 font_link = find_font_link(family->FamilyName);
4696 if (font_link != NULL &&
4697 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4704 * Try check the SystemLink list first for a replacement font.
4705 * We may find good replacements there.
4707 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4709 if(!strcmpiW(font_link->font_name, FaceName) ||
4710 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4712 TRACE("found entry in system list\n");
4713 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4715 const SYSTEM_LINKS *links;
4717 face = font_link_entry->face;
4718 if (!(face->scalable || can_use_bitmap))
4720 family = face->family;
4721 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4723 links = find_font_link(family->FamilyName);
4724 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4731 psub = NULL; /* substitution is no more relevant */
4733 /* If requested charset was DEFAULT_CHARSET then try using charset
4734 corresponding to the current ansi codepage */
4735 if (!csi.fs.fsCsb[0])
4738 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4739 FIXME("TCI failed on codepage %d\n", acp);
4740 csi.fs.fsCsb[0] = 0;
4742 lf.lfCharSet = csi.ciCharset;
4745 want_vertical = (lf.lfFaceName[0] == '@');
4747 /* Face families are in the top 4 bits of lfPitchAndFamily,
4748 so mask with 0xF0 before testing */
4750 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4751 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4752 strcpyW(lf.lfFaceName, defFixed);
4753 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4754 strcpyW(lf.lfFaceName, defSerif);
4755 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4756 strcpyW(lf.lfFaceName, defSans);
4758 strcpyW(lf.lfFaceName, defSans);
4759 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4760 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4761 font_link = find_font_link(family->FamilyName);
4762 face_list = get_face_list_from_family(family);
4763 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4764 if (!(face->scalable || can_use_bitmap))
4766 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4768 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4774 last_resort_family = NULL;
4775 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4776 font_link = find_font_link(family->FamilyName);
4777 face_list = get_face_list_from_family(family);
4778 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4779 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
4780 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4781 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4784 if(can_use_bitmap && !last_resort_family)
4785 last_resort_family = family;
4790 if(last_resort_family) {
4791 family = last_resort_family;
4792 csi.fs.fsCsb[0] = 0;
4796 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4797 face_list = get_face_list_from_family(family);
4798 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4799 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
4800 csi.fs.fsCsb[0] = 0;
4801 WARN("just using first face for now\n");
4804 if(can_use_bitmap && !last_resort_family)
4805 last_resort_family = family;
4808 if(!last_resort_family) {
4809 FIXME("can't find a single appropriate font - bailing\n");
4815 WARN("could only find a bitmap font - this will probably look awful!\n");
4816 family = last_resort_family;
4817 csi.fs.fsCsb[0] = 0;
4820 it = lf.lfItalic ? 1 : 0;
4821 bd = lf.lfWeight > 550 ? 1 : 0;
4823 height = lf.lfHeight;
4825 face = best = best_bitmap = NULL;
4826 font_link = find_font_link(family->FamilyName);
4827 face_list = get_face_list_from_family(family);
4828 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4830 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4831 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4836 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4837 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4838 new_score = (italic ^ it) + (bold ^ bd);
4839 if(!best || new_score <= score)
4841 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4842 italic, bold, it, bd);
4845 if(best->scalable && score == 0) break;
4849 newdiff = height - (signed int)(best->size.height);
4851 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4852 if(!best_bitmap || new_score < score ||
4853 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4855 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4858 if(score == 0 && diff == 0) break;
4865 face = best->scalable ? best : best_bitmap;
4866 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4867 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4870 height = lf.lfHeight;
4874 if(csi.fs.fsCsb[0]) {
4875 ret->charset = lf.lfCharSet;
4876 ret->codepage = csi.ciACP;
4879 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4881 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4882 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
4884 ret->aveWidth = height ? lf.lfWidth : 0;
4886 if(!face->scalable) {
4887 /* Windows uses integer scaling factors for bitmap fonts */
4888 INT scale, scaled_height;
4889 GdiFont *cachedfont;
4891 /* FIXME: rotation of bitmap fonts is ignored */
4892 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4894 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4895 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4896 dcmat.eM11 = dcmat.eM22 = 1.0;
4897 /* As we changed the matrix, we need to search the cache for the font again,
4898 * otherwise we might explode the cache. */
4899 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4900 TRACE("Found cached font after non-scalable matrix rescale!\n");
4905 calc_hash(&ret->font_desc);
4907 if (height != 0) height = diff;
4908 height += face->size.height;
4910 scale = (height + face->size.height - 1) / face->size.height;
4911 scaled_height = scale * face->size.height;
4912 /* Only jump to the next height if the difference <= 25% original height */
4913 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4914 /* The jump between unscaled and doubled is delayed by 1 */
4915 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4916 ret->scale_y = scale;
4918 width = face->size.x_ppem >> 6;
4919 height = face->size.y_ppem >> 6;
4923 TRACE("font scale y: %f\n", ret->scale_y);
4925 ret->ft_face = OpenFontFace(ret, face, width, height);
4934 ret->ntmFlags = face->ntmFlags;
4936 pick_charmap( ret->ft_face, ret->charset );
4938 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4939 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4940 ret->underline = lf.lfUnderline ? 0xff : 0;
4941 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4942 create_child_font_list(ret);
4944 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
4946 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4947 if (length != GDI_ERROR)
4949 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4950 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4951 TRACE("Loaded GSUB table of %i bytes\n",length);
4954 ret->aa_flags = HIWORD( face->flags );
4956 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4962 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
4964 switch (lf.lfQuality)
4966 case NONANTIALIASED_QUALITY:
4967 case ANTIALIASED_QUALITY:
4968 next->funcs->pSelectFont( dev, hfont, aa_flags );
4970 case CLEARTYPE_QUALITY:
4971 case CLEARTYPE_NATURAL_QUALITY:
4973 if (!*aa_flags) *aa_flags = ret->aa_flags;
4974 next->funcs->pSelectFont( dev, hfont, aa_flags );
4976 /* fixup the antialiasing flags for that font */
4979 case WINE_GGO_HRGB_BITMAP:
4980 case WINE_GGO_HBGR_BITMAP:
4981 case WINE_GGO_VRGB_BITMAP:
4982 case WINE_GGO_VBGR_BITMAP:
4983 if (is_subpixel_rendering_enabled()) break;
4984 *aa_flags = GGO_GRAY4_BITMAP;
4986 case GGO_GRAY2_BITMAP:
4987 case GGO_GRAY4_BITMAP:
4988 case GGO_GRAY8_BITMAP:
4989 case WINE_GGO_GRAY16_BITMAP:
4990 if (is_hinting_enabled())
4993 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
4995 TRACE( "font %s %d aa disabled by GASP\n",
4996 debugstr_w(lf.lfFaceName), lf.lfHeight );
4997 *aa_flags = GGO_BITMAP;
5002 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5003 release_font( physdev->font );
5004 physdev->font = ret;
5006 LeaveCriticalSection( &freetype_cs );
5007 release_dc_ptr( dc );
5008 return ret ? hfont : 0;
5011 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5018 id += IDS_FIRST_SCRIPT;
5019 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5020 if (!rsrc) return 0;
5021 hMem = LoadResource( gdi32_module, rsrc );
5022 if (!hMem) return 0;
5024 p = LockResource( hMem );
5026 while (id--) p += *p + 1;
5028 i = min(LF_FACESIZE - 1, *p);
5029 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5035 /***************************************************
5036 * create_enum_charset_list
5038 * This function creates charset enumeration list because in DEFAULT_CHARSET
5039 * case, the ANSI codepage's charset takes precedence over other charsets.
5040 * This function works as a filter other than DEFAULT_CHARSET case.
5042 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5047 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5048 csi.fs.fsCsb[0] != 0) {
5049 list->element[n].mask = csi.fs.fsCsb[0];
5050 list->element[n].charset = csi.ciCharset;
5051 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5054 else { /* charset is DEFAULT_CHARSET or invalid. */
5058 /* Set the current codepage's charset as the first element. */
5060 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5061 csi.fs.fsCsb[0] != 0) {
5062 list->element[n].mask = csi.fs.fsCsb[0];
5063 list->element[n].charset = csi.ciCharset;
5064 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5065 mask |= csi.fs.fsCsb[0];
5069 /* Fill out left elements. */
5070 for (i = 0; i < 32; i++) {
5072 fs.fsCsb[0] = 1L << i;
5074 if (fs.fsCsb[0] & mask)
5075 continue; /* skip, already added. */
5076 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5077 continue; /* skip, this is an invalid fsCsb bit. */
5079 list->element[n].mask = fs.fsCsb[0];
5080 list->element[n].charset = csi.ciCharset;
5081 load_script_name( i, list->element[n].name );
5082 mask |= fs.fsCsb[0];
5086 /* add catch all mask for remaining bits */
5089 list->element[n].mask = ~mask;
5090 list->element[n].charset = DEFAULT_CHARSET;
5091 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5100 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5101 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5106 if (face->cached_enum_data)
5109 *pelf = face->cached_enum_data->elf;
5110 *pntm = face->cached_enum_data->ntm;
5111 *ptype = face->cached_enum_data->type;
5115 font = alloc_font();
5117 if(face->scalable) {
5121 height = face->size.y_ppem >> 6;
5122 width = face->size.x_ppem >> 6;
5124 font->scale_y = 1.0;
5126 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5132 font->name = strdupW( family_name );
5133 font->ntmFlags = face->ntmFlags;
5135 if (get_outline_text_metrics(font))
5137 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5139 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5140 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5141 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5143 lstrcpynW(pelf->elfLogFont.lfFaceName,
5144 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5146 lstrcpynW(pelf->elfFullName,
5147 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5149 lstrcpynW(pelf->elfStyle,
5150 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5155 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5157 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5158 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5159 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5161 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5163 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5165 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5166 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5169 pntm->ntmTm.ntmFlags = face->ntmFlags;
5170 pntm->ntmFontSig = face->fs;
5172 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5174 pelf->elfLogFont.lfEscapement = 0;
5175 pelf->elfLogFont.lfOrientation = 0;
5176 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5177 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5178 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5179 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5180 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5181 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5182 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5183 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5184 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5185 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5186 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5189 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5190 *ptype |= TRUETYPE_FONTTYPE;
5191 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5192 *ptype |= DEVICE_FONTTYPE;
5193 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5194 *ptype |= RASTER_FONTTYPE;
5196 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5197 if (face->cached_enum_data)
5199 face->cached_enum_data->elf = *pelf;
5200 face->cached_enum_data->ntm = *pntm;
5201 face->cached_enum_data->type = *ptype;
5207 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5210 const struct list *face_list;
5212 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5214 face_list = get_face_list_from_family(family);
5215 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5216 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5221 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5223 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5225 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5228 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5229 FONTENUMPROCW proc, LPARAM lparam)
5232 NEWTEXTMETRICEXW ntm;
5236 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5237 for(i = 0; i < list->total; i++) {
5238 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5239 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5240 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5241 i = list->total; /* break out of loop after enumeration */
5245 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5246 /* use the DEFAULT_CHARSET case only if no other charset is present */
5247 if (list->element[i].charset == DEFAULT_CHARSET &&
5248 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5249 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5250 strcpyW(elf.elfScript, list->element[i].name);
5251 if (!elf.elfScript[0])
5252 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5254 /* Font Replacement */
5255 if (family != face->family)
5257 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5259 strcpyW(elf.elfFullName, face->FullName);
5261 strcpyW(elf.elfFullName, family->FamilyName);
5263 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5264 debugstr_w(elf.elfLogFont.lfFaceName),
5265 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5266 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5267 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5268 ntm.ntmTm.ntmFlags);
5269 /* release section before callback (FIXME) */
5270 LeaveCriticalSection( &freetype_cs );
5271 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5272 EnterCriticalSection( &freetype_cs );
5277 /*************************************************************
5278 * freetype_EnumFonts
5280 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5284 const struct list *face_list;
5286 struct enum_charset_list enum_charsets;
5290 lf.lfCharSet = DEFAULT_CHARSET;
5291 lf.lfPitchAndFamily = 0;
5292 lf.lfFaceName[0] = 0;
5296 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5298 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5301 EnterCriticalSection( &freetype_cs );
5302 if(plf->lfFaceName[0]) {
5304 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5307 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5308 debugstr_w(psub->to.name));
5310 strcpyW(lf.lfFaceName, psub->to.name);
5314 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5315 if (!family_matches(family, plf)) continue;
5316 face_list = get_face_list_from_family(family);
5317 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5318 if (!face_matches(family->FamilyName, face, plf)) continue;
5319 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5323 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5324 face_list = get_face_list_from_family(family);
5325 face = LIST_ENTRY(list_head(face_list), Face, entry);
5326 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5329 LeaveCriticalSection( &freetype_cs );
5333 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5335 pt->x.value = vec->x >> 6;
5336 pt->x.fract = (vec->x & 0x3f) << 10;
5337 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5338 pt->y.value = vec->y >> 6;
5339 pt->y.fract = (vec->y & 0x3f) << 10;
5340 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5344 /***************************************************
5345 * According to the MSDN documentation on WideCharToMultiByte,
5346 * certain codepages cannot set the default_used parameter.
5347 * This returns TRUE if the codepage can set that parameter, false else
5348 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5350 static BOOL codepage_sets_default_used(UINT codepage)
5364 * GSUB Table handling functions
5367 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5369 const GSUB_CoverageFormat1* cf1;
5373 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5375 int count = GET_BE_WORD(cf1->GlyphCount);
5377 TRACE("Coverage Format 1, %i glyphs\n",count);
5378 for (i = 0; i < count; i++)
5379 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5383 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5385 const GSUB_CoverageFormat2* cf2;
5388 cf2 = (const GSUB_CoverageFormat2*)cf1;
5390 count = GET_BE_WORD(cf2->RangeCount);
5391 TRACE("Coverage Format 2, %i ranges\n",count);
5392 for (i = 0; i < count; i++)
5394 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5396 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5397 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5399 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5400 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5406 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5411 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5413 const GSUB_ScriptList *script;
5414 const GSUB_Script *deflt = NULL;
5416 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5418 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5419 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5421 const GSUB_Script *scr;
5424 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5425 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5427 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5429 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5435 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5439 const GSUB_LangSys *Lang;
5441 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5443 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5445 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5446 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5448 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5451 offset = GET_BE_WORD(script->DefaultLangSys);
5454 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5460 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5463 const GSUB_FeatureList *feature;
5464 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5466 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5467 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5469 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5470 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5472 const GSUB_Feature *feat;
5473 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5480 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5484 const GSUB_LookupList *lookup;
5485 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5487 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5488 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5490 const GSUB_LookupTable *look;
5491 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5492 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5493 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5494 if (GET_BE_WORD(look->LookupType) != 1)
5495 FIXME("We only handle SubType 1\n");
5500 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5502 const GSUB_SingleSubstFormat1 *ssf1;
5503 offset = GET_BE_WORD(look->SubTable[j]);
5504 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5505 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5507 int offset = GET_BE_WORD(ssf1->Coverage);
5508 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5509 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5511 TRACE(" Glyph 0x%x ->",glyph);
5512 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5513 TRACE(" 0x%x\n",glyph);
5518 const GSUB_SingleSubstFormat2 *ssf2;
5522 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5523 offset = GET_BE_WORD(ssf1->Coverage);
5524 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5525 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5526 TRACE(" Coverage index %i\n",index);
5529 TRACE(" Glyph is 0x%x ->",glyph);
5530 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5531 TRACE("0x%x\n",glyph);
5540 static const char* get_opentype_script(const GdiFont *font)
5543 * I am not sure if this is the correct way to generate our script tag
5546 switch (font->charset)
5548 case ANSI_CHARSET: return "latn";
5549 case BALTIC_CHARSET: return "latn"; /* ?? */
5550 case CHINESEBIG5_CHARSET: return "hani";
5551 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5552 case GB2312_CHARSET: return "hani";
5553 case GREEK_CHARSET: return "grek";
5554 case HANGUL_CHARSET: return "hang";
5555 case RUSSIAN_CHARSET: return "cyrl";
5556 case SHIFTJIS_CHARSET: return "kana";
5557 case TURKISH_CHARSET: return "latn"; /* ?? */
5558 case VIETNAMESE_CHARSET: return "latn";
5559 case JOHAB_CHARSET: return "latn"; /* ?? */
5560 case ARABIC_CHARSET: return "arab";
5561 case HEBREW_CHARSET: return "hebr";
5562 case THAI_CHARSET: return "thai";
5563 default: return "latn";
5567 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5569 const GSUB_Header *header;
5570 const GSUB_Script *script;
5571 const GSUB_LangSys *language;
5572 const GSUB_Feature *feature;
5574 if (!font->GSUB_Table)
5577 header = font->GSUB_Table;
5579 script = GSUB_get_script_table(header, get_opentype_script(font));
5582 TRACE("Script not found\n");
5585 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5588 TRACE("Language not found\n");
5591 feature = GSUB_get_feature(header, language, "vrt2");
5593 feature = GSUB_get_feature(header, language, "vert");
5596 TRACE("vrt2/vert feature not found\n");
5599 return GSUB_apply_feature(header, feature, glyph);
5602 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5606 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5607 WCHAR wc = (WCHAR)glyph;
5609 BOOL *default_used_pointer;
5612 default_used_pointer = NULL;
5613 default_used = FALSE;
5614 if (codepage_sets_default_used(font->codepage))
5615 default_used_pointer = &default_used;
5616 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5618 if (font->codepage == CP_SYMBOL && wc < 0x100)
5619 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5624 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5625 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5629 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5631 if (glyph < 0x100) glyph += 0xf000;
5632 /* there is a number of old pre-Unicode "broken" TTFs, which
5633 do have symbols at U+00XX instead of U+f0XX */
5634 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5635 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5637 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5642 /*************************************************************
5643 * freetype_GetGlyphIndices
5645 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5647 struct freetype_physdev *physdev = get_freetype_dev( dev );
5650 BOOL got_default = FALSE;
5654 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5655 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5658 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5660 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5665 EnterCriticalSection( &freetype_cs );
5667 for(i = 0; i < count; i++)
5669 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5674 if (FT_IS_SFNT(physdev->font->ft_face))
5676 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5677 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5682 get_text_metrics(physdev->font, &textm);
5683 default_char = textm.tmDefaultChar;
5687 pgi[i] = default_char;
5690 LeaveCriticalSection( &freetype_cs );
5694 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5696 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5697 return !memcmp(matrix, &identity, sizeof(FMAT2));
5700 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5702 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5703 return !memcmp(matrix, &identity, sizeof(MAT2));
5706 static inline BYTE get_max_level( UINT format )
5710 case GGO_GRAY2_BITMAP: return 4;
5711 case GGO_GRAY4_BITMAP: return 16;
5712 case GGO_GRAY8_BITMAP: return 64;
5717 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5719 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5720 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5723 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5724 FT_Face ft_face = incoming_font->ft_face;
5725 GdiFont *font = incoming_font;
5726 FT_UInt glyph_index;
5727 DWORD width, height, pitch, needed = 0;
5728 FT_Bitmap ft_bitmap;
5730 INT left, right, top = 0, bottom = 0, adv;
5732 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5733 double widthRatio = 1.0;
5734 FT_Matrix transMat = identityMat;
5735 FT_Matrix transMatUnrotated;
5736 BOOL needsTransform = FALSE;
5737 BOOL tategaki = (font->GSUB_Table != NULL);
5738 UINT original_index;
5740 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5741 buflen, buf, lpmat);
5743 TRACE("font transform %f %f %f %f\n",
5744 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5745 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5747 if(format & GGO_GLYPH_INDEX) {
5748 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5749 original_index = glyph;
5750 format &= ~GGO_GLYPH_INDEX;
5752 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5753 ft_face = font->ft_face;
5754 original_index = glyph_index;
5757 if(format & GGO_UNHINTED) {
5758 load_flags |= FT_LOAD_NO_HINTING;
5759 format &= ~GGO_UNHINTED;
5762 /* tategaki never appears to happen to lower glyph index */
5763 if (glyph_index < TATEGAKI_LOWER_BOUND )
5766 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5767 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5768 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5769 font->gmsize * sizeof(GM*));
5771 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5772 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5774 *lpgm = FONT_GM(font,original_index)->gm;
5775 *abc = FONT_GM(font,original_index)->abc;
5776 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5777 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5778 lpgm->gmCellIncX, lpgm->gmCellIncY);
5779 return 1; /* FIXME */
5783 if (!font->gm[original_index / GM_BLOCK_SIZE])
5784 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5786 /* Scaling factor */
5791 get_text_metrics(font, &tm);
5793 widthRatio = (double)font->aveWidth;
5794 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5797 widthRatio = font->scale_y;
5799 /* Scaling transform */
5800 if (widthRatio != 1.0 || font->scale_y != 1.0)
5803 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5806 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5808 pFT_Matrix_Multiply(&scaleMat, &transMat);
5809 needsTransform = TRUE;
5812 /* Slant transform */
5813 if (font->fake_italic) {
5816 slantMat.xx = (1 << 16);
5817 slantMat.xy = ((1 << 16) >> 2);
5819 slantMat.yy = (1 << 16);
5820 pFT_Matrix_Multiply(&slantMat, &transMat);
5821 needsTransform = TRUE;
5824 /* Rotation transform */
5825 transMatUnrotated = transMat;
5826 if(font->orientation && !tategaki) {
5827 FT_Matrix rotationMat;
5829 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5830 pFT_Vector_Unit(&vecAngle, angle);
5831 rotationMat.xx = vecAngle.x;
5832 rotationMat.xy = -vecAngle.y;
5833 rotationMat.yx = -rotationMat.xy;
5834 rotationMat.yy = rotationMat.xx;
5836 pFT_Matrix_Multiply(&rotationMat, &transMat);
5837 needsTransform = TRUE;
5840 /* World transform */
5841 if (!is_identity_FMAT2(&font->font_desc.matrix))
5844 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5845 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
5846 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
5847 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5848 pFT_Matrix_Multiply(&worldMat, &transMat);
5849 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5850 needsTransform = TRUE;
5853 /* Extra transformation specified by caller */
5854 if (!is_identity_MAT2(lpmat))
5857 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5858 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
5859 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
5860 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5861 pFT_Matrix_Multiply(&extraMat, &transMat);
5862 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5863 needsTransform = TRUE;
5866 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
5868 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5871 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5875 if(!needsTransform) {
5876 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5877 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5878 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5880 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5881 bottom = (ft_face->glyph->metrics.horiBearingY -
5882 ft_face->glyph->metrics.height) & -64;
5883 lpgm->gmCellIncX = adv;
5884 lpgm->gmCellIncY = 0;
5891 for(xc = 0; xc < 2; xc++) {
5892 for(yc = 0; yc < 2; yc++) {
5893 vec.x = (ft_face->glyph->metrics.horiBearingX +
5894 xc * ft_face->glyph->metrics.width);
5895 vec.y = ft_face->glyph->metrics.horiBearingY -
5896 yc * ft_face->glyph->metrics.height;
5897 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5898 pFT_Vector_Transform(&vec, &transMat);
5899 if(xc == 0 && yc == 0) {
5900 left = right = vec.x;
5901 top = bottom = vec.y;
5903 if(vec.x < left) left = vec.x;
5904 else if(vec.x > right) right = vec.x;
5905 if(vec.y < bottom) bottom = vec.y;
5906 else if(vec.y > top) top = vec.y;
5911 right = (right + 63) & -64;
5912 bottom = bottom & -64;
5913 top = (top + 63) & -64;
5915 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5916 vec.x = ft_face->glyph->metrics.horiAdvance;
5918 pFT_Vector_Transform(&vec, &transMat);
5919 lpgm->gmCellIncX = (vec.x+63) >> 6;
5920 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5922 vec.x = ft_face->glyph->metrics.horiAdvance;
5924 pFT_Vector_Transform(&vec, &transMatUnrotated);
5925 adv = (vec.x+63) >> 6;
5928 lpgm->gmBlackBoxX = (right - left) >> 6;
5929 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5930 lpgm->gmptGlyphOrigin.x = left >> 6;
5931 lpgm->gmptGlyphOrigin.y = top >> 6;
5932 abc->abcA = left >> 6;
5933 abc->abcB = (right - left) >> 6;
5934 abc->abcC = adv - abc->abcA - abc->abcB;
5936 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5937 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5938 lpgm->gmCellIncX, lpgm->gmCellIncY);
5940 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5941 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5943 FONT_GM(font,original_index)->gm = *lpgm;
5944 FONT_GM(font,original_index)->abc = *abc;
5945 FONT_GM(font,original_index)->init = TRUE;
5948 if(format == GGO_METRICS)
5950 return 1; /* FIXME */
5953 if(ft_face->glyph->format != ft_glyph_format_outline &&
5954 (format == GGO_NATIVE || format == GGO_BEZIER))
5956 TRACE("loaded a bitmap\n");
5962 width = lpgm->gmBlackBoxX;
5963 height = lpgm->gmBlackBoxY;
5964 pitch = ((width + 31) >> 5) << 2;
5965 needed = pitch * height;
5967 if(!buf || !buflen) break;
5969 switch(ft_face->glyph->format) {
5970 case ft_glyph_format_bitmap:
5972 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5973 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5974 INT h = ft_face->glyph->bitmap.rows;
5976 memcpy(dst, src, w);
5977 src += ft_face->glyph->bitmap.pitch;
5983 case ft_glyph_format_outline:
5984 ft_bitmap.width = width;
5985 ft_bitmap.rows = height;
5986 ft_bitmap.pitch = pitch;
5987 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5988 ft_bitmap.buffer = buf;
5991 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5993 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5995 /* Note: FreeType will only set 'black' bits for us. */
5996 memset(buf, 0, needed);
5997 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6001 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6006 case GGO_GRAY2_BITMAP:
6007 case GGO_GRAY4_BITMAP:
6008 case GGO_GRAY8_BITMAP:
6009 case WINE_GGO_GRAY16_BITMAP:
6011 unsigned int max_level, row, col;
6014 width = lpgm->gmBlackBoxX;
6015 height = lpgm->gmBlackBoxY;
6016 pitch = (width + 3) / 4 * 4;
6017 needed = pitch * height;
6019 if(!buf || !buflen) break;
6021 max_level = get_max_level( format );
6023 switch(ft_face->glyph->format) {
6024 case ft_glyph_format_bitmap:
6026 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6027 INT h = ft_face->glyph->bitmap.rows;
6029 memset( buf, 0, needed );
6031 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6032 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6033 src += ft_face->glyph->bitmap.pitch;
6038 case ft_glyph_format_outline:
6040 ft_bitmap.width = width;
6041 ft_bitmap.rows = height;
6042 ft_bitmap.pitch = pitch;
6043 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6044 ft_bitmap.buffer = buf;
6047 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6049 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6051 memset(ft_bitmap.buffer, 0, buflen);
6053 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6055 if (max_level != 255)
6057 for (row = 0, start = buf; row < height; row++)
6059 for (col = 0, ptr = start; col < width; col++, ptr++)
6060 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6068 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6074 case WINE_GGO_HRGB_BITMAP:
6075 case WINE_GGO_HBGR_BITMAP:
6076 case WINE_GGO_VRGB_BITMAP:
6077 case WINE_GGO_VBGR_BITMAP:
6078 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6080 switch (ft_face->glyph->format)
6082 case FT_GLYPH_FORMAT_BITMAP:
6087 width = lpgm->gmBlackBoxX;
6088 height = lpgm->gmBlackBoxY;
6090 needed = pitch * height;
6092 if (!buf || !buflen) break;
6094 memset(buf, 0, buflen);
6096 src = ft_face->glyph->bitmap.buffer;
6097 src_pitch = ft_face->glyph->bitmap.pitch;
6099 height = min( height, ft_face->glyph->bitmap.rows );
6102 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6104 if ( src[x / 8] & masks[x % 8] )
6105 ((unsigned int *)dst)[x] = ~0u;
6114 case FT_GLYPH_FORMAT_OUTLINE:
6118 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6119 INT x_shift, y_shift;
6121 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6122 FT_Render_Mode render_mode =
6123 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6124 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6126 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6128 if ( render_mode == FT_RENDER_MODE_LCD)
6130 lpgm->gmBlackBoxX += 2;
6131 lpgm->gmptGlyphOrigin.x -= 1;
6135 lpgm->gmBlackBoxY += 2;
6136 lpgm->gmptGlyphOrigin.y += 1;
6140 width = lpgm->gmBlackBoxX;
6141 height = lpgm->gmBlackBoxY;
6143 needed = pitch * height;
6145 if (!buf || !buflen) break;
6147 memset(buf, 0, buflen);
6149 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6151 if ( needsTransform )
6152 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6154 if ( pFT_Library_SetLcdFilter )
6155 pFT_Library_SetLcdFilter( library, lcdfilter );
6156 pFT_Render_Glyph (ft_face->glyph, render_mode);
6158 src = ft_face->glyph->bitmap.buffer;
6159 src_pitch = ft_face->glyph->bitmap.pitch;
6160 src_width = ft_face->glyph->bitmap.width;
6161 src_height = ft_face->glyph->bitmap.rows;
6163 if ( render_mode == FT_RENDER_MODE_LCD)
6171 rgb_interval = src_pitch;
6176 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6177 if ( x_shift < 0 ) x_shift = 0;
6178 if ( x_shift + (src_width / hmul) > width )
6179 x_shift = width - (src_width / hmul);
6181 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6182 if ( y_shift < 0 ) y_shift = 0;
6183 if ( y_shift + (src_height / vmul) > height )
6184 y_shift = height - (src_height / vmul);
6186 dst += x_shift + y_shift * ( pitch / 4 );
6187 while ( src_height )
6189 for ( x = 0; x < src_width / hmul; x++ )
6193 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6194 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6195 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6196 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6200 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6201 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6202 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6203 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6206 src += src_pitch * vmul;
6215 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6227 int contour, point = 0, first_pt;
6228 FT_Outline *outline = &ft_face->glyph->outline;
6229 TTPOLYGONHEADER *pph;
6231 DWORD pph_start, cpfx, type;
6233 if(buflen == 0) buf = NULL;
6235 if (needsTransform && buf) {
6236 pFT_Outline_Transform(outline, &transMat);
6239 for(contour = 0; contour < outline->n_contours; contour++) {
6240 /* Ignore contours containing one point */
6241 if(point == outline->contours[contour]) {
6247 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6250 pph->dwType = TT_POLYGON_TYPE;
6251 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6253 needed += sizeof(*pph);
6255 while(point <= outline->contours[contour]) {
6256 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6257 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6258 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6262 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6265 } while(point <= outline->contours[contour] &&
6266 (outline->tags[point] & FT_Curve_Tag_On) ==
6267 (outline->tags[point-1] & FT_Curve_Tag_On));
6268 /* At the end of a contour Windows adds the start point, but
6270 if(point > outline->contours[contour] &&
6271 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6273 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6275 } else if(point <= outline->contours[contour] &&
6276 outline->tags[point] & FT_Curve_Tag_On) {
6277 /* add closing pt for bezier */
6279 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6287 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6290 pph->cb = needed - pph_start;
6296 /* Convert the quadratic Beziers to cubic Beziers.
6297 The parametric eqn for a cubic Bezier is, from PLRM:
6298 r(t) = at^3 + bt^2 + ct + r0
6299 with the control points:
6304 A quadratic Bezier has the form:
6305 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6307 So equating powers of t leads to:
6308 r1 = 2/3 p1 + 1/3 p0
6309 r2 = 2/3 p1 + 1/3 p2
6310 and of course r0 = p0, r3 = p2
6313 int contour, point = 0, first_pt;
6314 FT_Outline *outline = &ft_face->glyph->outline;
6315 TTPOLYGONHEADER *pph;
6317 DWORD pph_start, cpfx, type;
6318 FT_Vector cubic_control[4];
6319 if(buflen == 0) buf = NULL;
6321 if (needsTransform && buf) {
6322 pFT_Outline_Transform(outline, &transMat);
6325 for(contour = 0; contour < outline->n_contours; contour++) {
6327 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6330 pph->dwType = TT_POLYGON_TYPE;
6331 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6333 needed += sizeof(*pph);
6335 while(point <= outline->contours[contour]) {
6336 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6337 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6338 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6341 if(type == TT_PRIM_LINE) {
6343 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6347 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6350 /* FIXME: Possible optimization in endpoint calculation
6351 if there are two consecutive curves */
6352 cubic_control[0] = outline->points[point-1];
6353 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6354 cubic_control[0].x += outline->points[point].x + 1;
6355 cubic_control[0].y += outline->points[point].y + 1;
6356 cubic_control[0].x >>= 1;
6357 cubic_control[0].y >>= 1;
6359 if(point+1 > outline->contours[contour])
6360 cubic_control[3] = outline->points[first_pt];
6362 cubic_control[3] = outline->points[point+1];
6363 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6364 cubic_control[3].x += outline->points[point].x + 1;
6365 cubic_control[3].y += outline->points[point].y + 1;
6366 cubic_control[3].x >>= 1;
6367 cubic_control[3].y >>= 1;
6370 /* r1 = 1/3 p0 + 2/3 p1
6371 r2 = 1/3 p2 + 2/3 p1 */
6372 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6373 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6374 cubic_control[2] = cubic_control[1];
6375 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6376 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6377 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6378 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6380 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6381 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6382 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6387 } while(point <= outline->contours[contour] &&
6388 (outline->tags[point] & FT_Curve_Tag_On) ==
6389 (outline->tags[point-1] & FT_Curve_Tag_On));
6390 /* At the end of a contour Windows adds the start point,
6391 but only for Beziers and we've already done that.
6393 if(point <= outline->contours[contour] &&
6394 outline->tags[point] & FT_Curve_Tag_On) {
6395 /* This is the closing pt of a bezier, but we've already
6396 added it, so just inc point and carry on */
6403 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6406 pph->cb = needed - pph_start;
6412 FIXME("Unsupported format %d\n", format);
6418 static BOOL get_bitmap_text_metrics(GdiFont *font)
6420 FT_Face ft_face = font->ft_face;
6421 FT_WinFNT_HeaderRec winfnt_header;
6422 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6423 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6424 font->potm->otmSize = size;
6426 #define TM font->potm->otmTextMetrics
6427 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6429 TM.tmHeight = winfnt_header.pixel_height;
6430 TM.tmAscent = winfnt_header.ascent;
6431 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6432 TM.tmInternalLeading = winfnt_header.internal_leading;
6433 TM.tmExternalLeading = winfnt_header.external_leading;
6434 TM.tmAveCharWidth = winfnt_header.avg_width;
6435 TM.tmMaxCharWidth = winfnt_header.max_width;
6436 TM.tmWeight = winfnt_header.weight;
6438 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6439 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6440 TM.tmFirstChar = winfnt_header.first_char;
6441 TM.tmLastChar = winfnt_header.last_char;
6442 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6443 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6444 TM.tmItalic = winfnt_header.italic;
6445 TM.tmUnderlined = font->underline;
6446 TM.tmStruckOut = font->strikeout;
6447 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6448 TM.tmCharSet = winfnt_header.charset;
6452 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6453 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6454 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6455 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6456 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6457 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6458 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6459 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6461 TM.tmDigitizedAspectX = 96; /* FIXME */
6462 TM.tmDigitizedAspectY = 96; /* FIXME */
6464 TM.tmLastChar = 255;
6465 TM.tmDefaultChar = 32;
6466 TM.tmBreakChar = 32;
6467 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6468 TM.tmUnderlined = font->underline;
6469 TM.tmStruckOut = font->strikeout;
6470 /* NB inverted meaning of TMPF_FIXED_PITCH */
6471 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6472 TM.tmCharSet = font->charset;
6480 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6482 double scale_x, scale_y;
6486 scale_x = (double)font->aveWidth;
6487 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6490 scale_x = font->scale_y;
6492 scale_x *= fabs(font->font_desc.matrix.eM11);
6493 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6495 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6496 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6498 SCALE_Y(ptm->tmHeight);
6499 SCALE_Y(ptm->tmAscent);
6500 SCALE_Y(ptm->tmDescent);
6501 SCALE_Y(ptm->tmInternalLeading);
6502 SCALE_Y(ptm->tmExternalLeading);
6503 SCALE_Y(ptm->tmOverhang);
6505 SCALE_X(ptm->tmAveCharWidth);
6506 SCALE_X(ptm->tmMaxCharWidth);
6512 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6514 double scale_x, scale_y;
6518 scale_x = (double)font->aveWidth;
6519 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6522 scale_x = font->scale_y;
6524 scale_x *= fabs(font->font_desc.matrix.eM11);
6525 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6527 scale_font_metrics(font, &potm->otmTextMetrics);
6529 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6530 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6532 SCALE_Y(potm->otmAscent);
6533 SCALE_Y(potm->otmDescent);
6534 SCALE_Y(potm->otmLineGap);
6535 SCALE_Y(potm->otmsCapEmHeight);
6536 SCALE_Y(potm->otmsXHeight);
6537 SCALE_Y(potm->otmrcFontBox.top);
6538 SCALE_Y(potm->otmrcFontBox.bottom);
6539 SCALE_X(potm->otmrcFontBox.left);
6540 SCALE_X(potm->otmrcFontBox.right);
6541 SCALE_Y(potm->otmMacAscent);
6542 SCALE_Y(potm->otmMacDescent);
6543 SCALE_Y(potm->otmMacLineGap);
6544 SCALE_X(potm->otmptSubscriptSize.x);
6545 SCALE_Y(potm->otmptSubscriptSize.y);
6546 SCALE_X(potm->otmptSubscriptOffset.x);
6547 SCALE_Y(potm->otmptSubscriptOffset.y);
6548 SCALE_X(potm->otmptSuperscriptSize.x);
6549 SCALE_Y(potm->otmptSuperscriptSize.y);
6550 SCALE_X(potm->otmptSuperscriptOffset.x);
6551 SCALE_Y(potm->otmptSuperscriptOffset.y);
6552 SCALE_Y(potm->otmsStrikeoutSize);
6553 SCALE_Y(potm->otmsStrikeoutPosition);
6554 SCALE_Y(potm->otmsUnderscoreSize);
6555 SCALE_Y(potm->otmsUnderscorePosition);
6561 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6565 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6567 /* Make sure that the font has sane width/height ratio */
6570 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6572 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6577 *ptm = font->potm->otmTextMetrics;
6578 scale_font_metrics(font, ptm);
6582 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6586 for(i = 0; i < ft_face->num_charmaps; i++)
6588 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6594 static BOOL get_outline_text_metrics(GdiFont *font)
6597 FT_Face ft_face = font->ft_face;
6598 UINT needed, lenfam, lensty, lenface, lenfull;
6600 TT_HoriHeader *pHori;
6601 TT_Postscript *pPost;
6602 FT_Fixed x_scale, y_scale;
6603 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6605 INT ascent, descent;
6607 TRACE("font=%p\n", font);
6609 if(!FT_IS_SCALABLE(ft_face))
6612 needed = sizeof(*font->potm);
6614 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6615 family_nameW = strdupW(font->name);
6617 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6619 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6622 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6623 style_nameW = towstr( CP_ACP, ft_face->style_name );
6625 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6627 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6629 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6632 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6633 face_nameW = strdupW(font->name);
6635 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6636 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6638 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6640 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6643 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6644 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6645 full_nameW = strdupW(fake_nameW);
6647 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6649 /* These names should be read from the TT name table */
6651 /* length of otmpFamilyName */
6654 /* length of otmpFaceName */
6657 /* length of otmpStyleName */
6660 /* length of otmpFullName */
6664 x_scale = ft_face->size->metrics.x_scale;
6665 y_scale = ft_face->size->metrics.y_scale;
6667 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6669 FIXME("Can't find OS/2 table - not TT font?\n");
6673 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6675 FIXME("Can't find HHEA table - not TT font?\n");
6679 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6681 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6682 pOS2->usWinAscent, pOS2->usWinDescent,
6683 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6684 pOS2->xAvgCharWidth,
6685 ft_face->ascender, ft_face->descender, ft_face->height,
6686 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6687 ft_face->bbox.yMax, ft_face->bbox.yMin);
6689 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6690 font->potm->otmSize = needed;
6692 #define TM font->potm->otmTextMetrics
6694 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6695 ascent = pHori->Ascender;
6696 descent = -pHori->Descender;
6698 ascent = pOS2->usWinAscent;
6699 descent = pOS2->usWinDescent;
6702 font->ntmCellHeight = ascent + descent;
6703 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6706 TM.tmAscent = font->yMax;
6707 TM.tmDescent = -font->yMin;
6708 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6710 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6711 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6712 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6713 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6716 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6719 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6721 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6722 ((ascent + descent) -
6723 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6725 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6726 if (TM.tmAveCharWidth == 0) {
6727 TM.tmAveCharWidth = 1;
6729 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6730 TM.tmWeight = FW_REGULAR;
6731 if (font->fake_bold)
6732 TM.tmWeight = FW_BOLD;
6735 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6737 if (pOS2->usWeightClass > FW_MEDIUM)
6738 TM.tmWeight = pOS2->usWeightClass;
6740 else if (pOS2->usWeightClass <= FW_MEDIUM)
6741 TM.tmWeight = pOS2->usWeightClass;
6744 TM.tmDigitizedAspectX = 96; /* FIXME */
6745 TM.tmDigitizedAspectY = 96; /* FIXME */
6746 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6747 * symbol range to 0 - f0ff
6750 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6755 case 1257: /* Baltic */
6756 TM.tmLastChar = 0xf8fd;
6759 TM.tmLastChar = 0xf0ff;
6761 TM.tmBreakChar = 0x20;
6762 TM.tmDefaultChar = 0x1f;
6766 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6767 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6769 if(pOS2->usFirstCharIndex <= 1)
6770 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6771 else if (pOS2->usFirstCharIndex > 0xff)
6772 TM.tmBreakChar = 0x20;
6774 TM.tmBreakChar = pOS2->usFirstCharIndex;
6775 TM.tmDefaultChar = TM.tmBreakChar - 1;
6777 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6778 TM.tmUnderlined = font->underline;
6779 TM.tmStruckOut = font->strikeout;
6781 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6782 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6783 (pOS2->version == 0xFFFFU ||
6784 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6785 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6787 TM.tmPitchAndFamily = 0;
6789 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6791 case PAN_FAMILY_SCRIPT:
6792 TM.tmPitchAndFamily |= FF_SCRIPT;
6795 case PAN_FAMILY_DECORATIVE:
6796 TM.tmPitchAndFamily |= FF_DECORATIVE;
6801 case PAN_FAMILY_TEXT_DISPLAY:
6802 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6803 /* which is clearly not what the panose spec says. */
6805 if(TM.tmPitchAndFamily == 0 || /* fixed */
6806 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6807 TM.tmPitchAndFamily = FF_MODERN;
6810 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6815 TM.tmPitchAndFamily |= FF_DONTCARE;
6818 case PAN_SERIF_COVE:
6819 case PAN_SERIF_OBTUSE_COVE:
6820 case PAN_SERIF_SQUARE_COVE:
6821 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6822 case PAN_SERIF_SQUARE:
6823 case PAN_SERIF_THIN:
6824 case PAN_SERIF_BONE:
6825 case PAN_SERIF_EXAGGERATED:
6826 case PAN_SERIF_TRIANGLE:
6827 TM.tmPitchAndFamily |= FF_ROMAN;
6830 case PAN_SERIF_NORMAL_SANS:
6831 case PAN_SERIF_OBTUSE_SANS:
6832 case PAN_SERIF_PERP_SANS:
6833 case PAN_SERIF_FLARED:
6834 case PAN_SERIF_ROUNDED:
6835 TM.tmPitchAndFamily |= FF_SWISS;
6842 if(FT_IS_SCALABLE(ft_face))
6843 TM.tmPitchAndFamily |= TMPF_VECTOR;
6845 if(FT_IS_SFNT(ft_face))
6847 if (font->ntmFlags & NTM_PS_OPENTYPE)
6848 TM.tmPitchAndFamily |= TMPF_DEVICE;
6850 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6853 TM.tmCharSet = font->charset;
6855 font->potm->otmFiller = 0;
6856 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6857 font->potm->otmfsSelection = pOS2->fsSelection;
6858 font->potm->otmfsType = pOS2->fsType;
6859 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6860 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6861 font->potm->otmItalicAngle = 0; /* POST table */
6862 font->potm->otmEMSquare = ft_face->units_per_EM;
6863 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6864 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6865 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6866 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6867 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6868 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6869 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6870 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6871 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6872 font->potm->otmMacAscent = TM.tmAscent;
6873 font->potm->otmMacDescent = -TM.tmDescent;
6874 font->potm->otmMacLineGap = font->potm->otmLineGap;
6875 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6876 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6877 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6878 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6879 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6880 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6881 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6882 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6883 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6884 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6885 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6887 font->potm->otmsUnderscoreSize = 0;
6888 font->potm->otmsUnderscorePosition = 0;
6890 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6891 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6895 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6896 cp = (char*)font->potm + sizeof(*font->potm);
6897 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6898 strcpyW((WCHAR*)cp, family_nameW);
6900 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6901 strcpyW((WCHAR*)cp, style_nameW);
6903 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6904 strcpyW((WCHAR*)cp, face_nameW);
6906 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6907 strcpyW((WCHAR*)cp, full_nameW);
6911 HeapFree(GetProcessHeap(), 0, style_nameW);
6912 HeapFree(GetProcessHeap(), 0, family_nameW);
6913 HeapFree(GetProcessHeap(), 0, face_nameW);
6914 HeapFree(GetProcessHeap(), 0, full_nameW);
6918 /*************************************************************
6919 * freetype_GetGlyphOutline
6921 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6922 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6924 struct freetype_physdev *physdev = get_freetype_dev( dev );
6930 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6931 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6935 EnterCriticalSection( &freetype_cs );
6936 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
6937 LeaveCriticalSection( &freetype_cs );
6941 /*************************************************************
6942 * freetype_GetTextMetrics
6944 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6946 struct freetype_physdev *physdev = get_freetype_dev( dev );
6951 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6952 return dev->funcs->pGetTextMetrics( dev, metrics );
6956 EnterCriticalSection( &freetype_cs );
6957 ret = get_text_metrics( physdev->font, metrics );
6958 LeaveCriticalSection( &freetype_cs );
6962 /*************************************************************
6963 * freetype_GetOutlineTextMetrics
6965 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6967 struct freetype_physdev *physdev = get_freetype_dev( dev );
6972 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6973 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6976 TRACE("font=%p\n", physdev->font);
6978 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6981 EnterCriticalSection( &freetype_cs );
6983 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6985 if(cbSize >= physdev->font->potm->otmSize)
6987 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6988 scale_outline_font_metrics(physdev->font, potm);
6990 ret = physdev->font->potm->otmSize;
6992 LeaveCriticalSection( &freetype_cs );
6996 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6998 child->font = alloc_font();
6999 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7000 if(!child->font->ft_face)
7002 free_font(child->font);
7007 child->font->font_desc = font->font_desc;
7008 child->font->ntmFlags = child->face->ntmFlags;
7009 child->font->orientation = font->orientation;
7010 child->font->scale_y = font->scale_y;
7011 child->font->name = strdupW(child->face->family->FamilyName);
7012 child->font->base_font = font;
7013 TRACE("created child font %p for base %p\n", child->font, font);
7017 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7020 CHILD_FONT *child_font;
7023 font = font->base_font;
7025 *linked_font = font;
7027 if((*glyph = get_glyph_index(font, c)))
7029 *glyph = get_GSUB_vert_glyph(font, *glyph);
7033 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7035 if(!child_font->font)
7036 if(!load_child_font(font, child_font))
7039 if(!child_font->font->ft_face)
7041 g = get_glyph_index(child_font->font, c);
7042 g = get_GSUB_vert_glyph(child_font->font, g);
7046 *linked_font = child_font->font;
7053 /*************************************************************
7054 * freetype_GetCharWidth
7056 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7058 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7062 struct freetype_physdev *physdev = get_freetype_dev( dev );
7066 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7067 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7070 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7073 EnterCriticalSection( &freetype_cs );
7074 for(c = firstChar; c <= lastChar; c++) {
7075 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7076 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7078 LeaveCriticalSection( &freetype_cs );
7082 /*************************************************************
7083 * freetype_GetCharABCWidths
7085 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7087 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7090 struct freetype_physdev *physdev = get_freetype_dev( dev );
7094 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7095 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7098 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7101 EnterCriticalSection( &freetype_cs );
7103 for(c = firstChar; c <= lastChar; c++, buffer++)
7104 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7106 LeaveCriticalSection( &freetype_cs );
7110 /*************************************************************
7111 * freetype_GetCharABCWidthsI
7113 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7115 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7118 struct freetype_physdev *physdev = get_freetype_dev( dev );
7122 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7123 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7126 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7130 EnterCriticalSection( &freetype_cs );
7132 for(c = 0; c < count; c++, buffer++)
7133 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7134 &gm, buffer, 0, NULL, &identity );
7136 LeaveCriticalSection( &freetype_cs );
7140 /*************************************************************
7141 * freetype_GetTextExtentExPoint
7143 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7145 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7149 struct freetype_physdev *physdev = get_freetype_dev( dev );
7153 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7154 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7157 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7160 EnterCriticalSection( &freetype_cs );
7162 for (idx = pos = 0; idx < count; idx++)
7164 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7165 pos += abc.abcA + abc.abcB + abc.abcC;
7169 LeaveCriticalSection( &freetype_cs );
7173 /*************************************************************
7174 * freetype_GetTextExtentExPointI
7176 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7178 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7182 struct freetype_physdev *physdev = get_freetype_dev( dev );
7186 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7187 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7190 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7193 EnterCriticalSection( &freetype_cs );
7195 for (idx = pos = 0; idx < count; idx++)
7197 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7198 &gm, &abc, 0, NULL, &identity );
7199 pos += abc.abcA + abc.abcB + abc.abcC;
7203 LeaveCriticalSection( &freetype_cs );
7207 /*************************************************************
7208 * freetype_GetFontData
7210 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7212 struct freetype_physdev *physdev = get_freetype_dev( dev );
7216 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7217 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7220 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7221 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7222 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7224 return get_font_data( physdev->font, table, offset, buf, cbData );
7227 /*************************************************************
7228 * freetype_GetTextFace
7230 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7233 struct freetype_physdev *physdev = get_freetype_dev( dev );
7237 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7238 return dev->funcs->pGetTextFace( dev, count, str );
7241 n = strlenW(physdev->font->name) + 1;
7244 lstrcpynW(str, physdev->font->name, count);
7250 /*************************************************************
7251 * freetype_GetTextCharsetInfo
7253 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7255 struct freetype_physdev *physdev = get_freetype_dev( dev );
7259 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7260 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7262 if (fs) *fs = physdev->font->fs;
7263 return physdev->font->charset;
7266 /* Retrieve a list of supported Unicode ranges for a given font.
7267 * Can be called with NULL gs to calculate the buffer size. Returns
7268 * the number of ranges found.
7270 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7272 DWORD num_ranges = 0;
7274 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7277 FT_ULong char_code, char_code_prev;
7280 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7282 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7283 face->num_glyphs, glyph_code, char_code);
7285 if (!glyph_code) return 0;
7289 gs->ranges[0].wcLow = (USHORT)char_code;
7290 gs->ranges[0].cGlyphs = 0;
7291 gs->cGlyphsSupported = 0;
7297 if (char_code < char_code_prev)
7299 ERR("expected increasing char code from FT_Get_Next_Char\n");
7302 if (char_code - char_code_prev > 1)
7307 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7308 gs->ranges[num_ranges - 1].cGlyphs = 1;
7309 gs->cGlyphsSupported++;
7314 gs->ranges[num_ranges - 1].cGlyphs++;
7315 gs->cGlyphsSupported++;
7317 char_code_prev = char_code;
7318 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7322 FIXME("encoding %u not supported\n", face->charmap->encoding);
7327 /*************************************************************
7328 * freetype_GetFontUnicodeRanges
7330 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7332 struct freetype_physdev *physdev = get_freetype_dev( dev );
7333 DWORD size, num_ranges;
7337 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7338 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7341 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7342 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7345 glyphset->cbThis = size;
7346 glyphset->cRanges = num_ranges;
7347 glyphset->flAccel = 0;
7352 /*************************************************************
7353 * freetype_FontIsLinked
7355 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7357 struct freetype_physdev *physdev = get_freetype_dev( dev );
7362 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7363 return dev->funcs->pFontIsLinked( dev );
7367 EnterCriticalSection( &freetype_cs );
7368 ret = !list_empty(&physdev->font->child_fonts);
7369 LeaveCriticalSection( &freetype_cs );
7373 /*************************************************************************
7374 * GetRasterizerCaps (GDI32.@)
7376 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7378 lprs->nSize = sizeof(RASTERIZER_STATUS);
7379 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7380 lprs->nLanguageID = 0;
7384 /*************************************************************
7385 * freetype_GdiRealizationInfo
7387 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7389 struct freetype_physdev *physdev = get_freetype_dev( dev );
7390 realization_info_t *info = ptr;
7394 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7395 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7398 FIXME("(%p, %p): stub!\n", physdev->font, info);
7401 if(FT_IS_SCALABLE(physdev->font->ft_face))
7404 info->cache_num = physdev->font->cache_num;
7405 info->unknown2 = -1;
7409 /*************************************************************************
7410 * Kerning support for TrueType fonts
7412 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7414 struct TT_kern_table
7420 struct TT_kern_subtable
7429 USHORT horizontal : 1;
7431 USHORT cross_stream: 1;
7432 USHORT override : 1;
7433 USHORT reserved1 : 4;
7439 struct TT_format0_kern_subtable
7443 USHORT entrySelector;
7454 static DWORD parse_format0_kern_subtable(GdiFont *font,
7455 const struct TT_format0_kern_subtable *tt_f0_ks,
7456 const USHORT *glyph_to_char,
7457 KERNINGPAIR *kern_pair, DWORD cPairs)
7460 const struct TT_kern_pair *tt_kern_pair;
7462 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7464 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7466 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7467 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7468 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7470 if (!kern_pair || !cPairs)
7473 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7475 nPairs = min(nPairs, cPairs);
7477 for (i = 0; i < nPairs; i++)
7479 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7480 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7481 /* this algorithm appears to better match what Windows does */
7482 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7483 if (kern_pair->iKernAmount < 0)
7485 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7486 kern_pair->iKernAmount -= font->ppem;
7488 else if (kern_pair->iKernAmount > 0)
7490 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7491 kern_pair->iKernAmount += font->ppem;
7493 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7495 TRACE("left %u right %u value %d\n",
7496 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7500 TRACE("copied %u entries\n", nPairs);
7504 /*************************************************************
7505 * freetype_GetKerningPairs
7507 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7511 const struct TT_kern_table *tt_kern_table;
7512 const struct TT_kern_subtable *tt_kern_subtable;
7514 USHORT *glyph_to_char;
7516 struct freetype_physdev *physdev = get_freetype_dev( dev );
7518 if (!(font = physdev->font))
7520 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7521 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7525 EnterCriticalSection( &freetype_cs );
7526 if (font->total_kern_pairs != (DWORD)-1)
7528 if (cPairs && kern_pair)
7530 cPairs = min(cPairs, font->total_kern_pairs);
7531 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7533 else cPairs = font->total_kern_pairs;
7535 LeaveCriticalSection( &freetype_cs );
7539 font->total_kern_pairs = 0;
7541 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7543 if (length == GDI_ERROR)
7545 TRACE("no kerning data in the font\n");
7546 LeaveCriticalSection( &freetype_cs );
7550 buf = HeapAlloc(GetProcessHeap(), 0, length);
7553 WARN("Out of memory\n");
7554 LeaveCriticalSection( &freetype_cs );
7558 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7560 /* build a glyph index to char code map */
7561 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7564 WARN("Out of memory allocating a glyph index to char code map\n");
7565 HeapFree(GetProcessHeap(), 0, buf);
7566 LeaveCriticalSection( &freetype_cs );
7570 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7576 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7578 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7579 font->ft_face->num_glyphs, glyph_code, char_code);
7583 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7585 /* FIXME: This doesn't match what Windows does: it does some fancy
7586 * things with duplicate glyph index to char code mappings, while
7587 * we just avoid overriding existing entries.
7589 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7590 glyph_to_char[glyph_code] = (USHORT)char_code;
7592 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7599 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7600 for (n = 0; n <= 65535; n++)
7601 glyph_to_char[n] = (USHORT)n;
7604 tt_kern_table = buf;
7605 nTables = GET_BE_WORD(tt_kern_table->nTables);
7606 TRACE("version %u, nTables %u\n",
7607 GET_BE_WORD(tt_kern_table->version), nTables);
7609 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7611 for (i = 0; i < nTables; i++)
7613 struct TT_kern_subtable tt_kern_subtable_copy;
7615 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7616 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7617 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7619 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7620 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7621 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7623 /* According to the TrueType specification this is the only format
7624 * that will be properly interpreted by Windows and OS/2
7626 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7628 DWORD new_chunk, old_total = font->total_kern_pairs;
7630 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7631 glyph_to_char, NULL, 0);
7632 font->total_kern_pairs += new_chunk;
7634 if (!font->kern_pairs)
7635 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7636 font->total_kern_pairs * sizeof(*font->kern_pairs));
7638 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7639 font->total_kern_pairs * sizeof(*font->kern_pairs));
7641 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7642 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7645 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7647 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7650 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7651 HeapFree(GetProcessHeap(), 0, buf);
7653 if (cPairs && kern_pair)
7655 cPairs = min(cPairs, font->total_kern_pairs);
7656 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7658 else cPairs = font->total_kern_pairs;
7660 LeaveCriticalSection( &freetype_cs );
7664 static const struct gdi_dc_funcs freetype_funcs =
7666 NULL, /* pAbortDoc */
7667 NULL, /* pAbortPath */
7668 NULL, /* pAlphaBlend */
7669 NULL, /* pAngleArc */
7672 NULL, /* pBeginPath */
7673 NULL, /* pBlendImage */
7675 NULL, /* pCloseFigure */
7676 NULL, /* pCreateCompatibleDC */
7677 freetype_CreateDC, /* pCreateDC */
7678 freetype_DeleteDC, /* pDeleteDC */
7679 NULL, /* pDeleteObject */
7680 NULL, /* pDeviceCapabilities */
7681 NULL, /* pEllipse */
7683 NULL, /* pEndPage */
7684 NULL, /* pEndPath */
7685 freetype_EnumFonts, /* pEnumFonts */
7686 NULL, /* pEnumICMProfiles */
7687 NULL, /* pExcludeClipRect */
7688 NULL, /* pExtDeviceMode */
7689 NULL, /* pExtEscape */
7690 NULL, /* pExtFloodFill */
7691 NULL, /* pExtSelectClipRgn */
7692 NULL, /* pExtTextOut */
7693 NULL, /* pFillPath */
7694 NULL, /* pFillRgn */
7695 NULL, /* pFlattenPath */
7696 freetype_FontIsLinked, /* pFontIsLinked */
7697 NULL, /* pFrameRgn */
7698 NULL, /* pGdiComment */
7699 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7700 NULL, /* pGetBoundsRect */
7701 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7702 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7703 freetype_GetCharWidth, /* pGetCharWidth */
7704 NULL, /* pGetDeviceCaps */
7705 NULL, /* pGetDeviceGammaRamp */
7706 freetype_GetFontData, /* pGetFontData */
7707 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7708 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7709 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7710 NULL, /* pGetICMProfile */
7711 NULL, /* pGetImage */
7712 freetype_GetKerningPairs, /* pGetKerningPairs */
7713 NULL, /* pGetNearestColor */
7714 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7715 NULL, /* pGetPixel */
7716 NULL, /* pGetSystemPaletteEntries */
7717 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7718 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7719 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7720 freetype_GetTextFace, /* pGetTextFace */
7721 freetype_GetTextMetrics, /* pGetTextMetrics */
7722 NULL, /* pGradientFill */
7723 NULL, /* pIntersectClipRect */
7724 NULL, /* pInvertRgn */
7726 NULL, /* pModifyWorldTransform */
7728 NULL, /* pOffsetClipRgn */
7729 NULL, /* pOffsetViewportOrg */
7730 NULL, /* pOffsetWindowOrg */
7731 NULL, /* pPaintRgn */
7734 NULL, /* pPolyBezier */
7735 NULL, /* pPolyBezierTo */
7736 NULL, /* pPolyDraw */
7737 NULL, /* pPolyPolygon */
7738 NULL, /* pPolyPolyline */
7739 NULL, /* pPolygon */
7740 NULL, /* pPolyline */
7741 NULL, /* pPolylineTo */
7742 NULL, /* pPutImage */
7743 NULL, /* pRealizeDefaultPalette */
7744 NULL, /* pRealizePalette */
7745 NULL, /* pRectangle */
7746 NULL, /* pResetDC */
7747 NULL, /* pRestoreDC */
7748 NULL, /* pRoundRect */
7750 NULL, /* pScaleViewportExt */
7751 NULL, /* pScaleWindowExt */
7752 NULL, /* pSelectBitmap */
7753 NULL, /* pSelectBrush */
7754 NULL, /* pSelectClipPath */
7755 freetype_SelectFont, /* pSelectFont */
7756 NULL, /* pSelectPalette */
7757 NULL, /* pSelectPen */
7758 NULL, /* pSetArcDirection */
7759 NULL, /* pSetBkColor */
7760 NULL, /* pSetBkMode */
7761 NULL, /* pSetDCBrushColor */
7762 NULL, /* pSetDCPenColor */
7763 NULL, /* pSetDIBColorTable */
7764 NULL, /* pSetDIBitsToDevice */
7765 NULL, /* pSetDeviceClipping */
7766 NULL, /* pSetDeviceGammaRamp */
7767 NULL, /* pSetLayout */
7768 NULL, /* pSetMapMode */
7769 NULL, /* pSetMapperFlags */
7770 NULL, /* pSetPixel */
7771 NULL, /* pSetPolyFillMode */
7772 NULL, /* pSetROP2 */
7773 NULL, /* pSetRelAbs */
7774 NULL, /* pSetStretchBltMode */
7775 NULL, /* pSetTextAlign */
7776 NULL, /* pSetTextCharacterExtra */
7777 NULL, /* pSetTextColor */
7778 NULL, /* pSetTextJustification */
7779 NULL, /* pSetViewportExt */
7780 NULL, /* pSetViewportOrg */
7781 NULL, /* pSetWindowExt */
7782 NULL, /* pSetWindowOrg */
7783 NULL, /* pSetWorldTransform */
7784 NULL, /* pStartDoc */
7785 NULL, /* pStartPage */
7786 NULL, /* pStretchBlt */
7787 NULL, /* pStretchDIBits */
7788 NULL, /* pStrokeAndFillPath */
7789 NULL, /* pStrokePath */
7790 NULL, /* pUnrealizePalette */
7791 NULL, /* pWidenPath */
7792 NULL, /* wine_get_wgl_driver */
7793 GDI_PRIORITY_FONT_DRV /* priority */
7796 #else /* HAVE_FREETYPE */
7798 /*************************************************************************/
7800 BOOL WineEngInit(void)
7805 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7807 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7811 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7813 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7817 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7819 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7823 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7824 LPCWSTR font_file, LPCWSTR font_path )
7830 /*************************************************************************
7831 * GetRasterizerCaps (GDI32.@)
7833 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7835 lprs->nSize = sizeof(RASTERIZER_STATUS);
7837 lprs->nLanguageID = 0;
7841 #endif /* HAVE_FREETYPE */