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);
540 static void remove_face_from_cache( Face *face );
542 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
543 'W','i','n','d','o','w','s',' ','N','T','\\',
544 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
545 'S','y','s','t','e','m','L','i','n','k',0};
547 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
548 'F','o','n','t','L','i','n','k','\\',
549 'S','y','s','t','e','m','L','i','n','k',0};
551 /****************************************
552 * Notes on .fon files
554 * The fonts System, FixedSys and Terminal are special. There are typically multiple
555 * versions installed for different resolutions and codepages. Windows stores which one to use
556 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
558 * FIXEDFON.FON FixedSys
560 * OEMFONT.FON Terminal
561 * LogPixels Current dpi set by the display control panel applet
562 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
563 * also has a LogPixels value that appears to mirror this)
565 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
566 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
567 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
568 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
569 * so that makes sense.
571 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
572 * to be mapped into the registry on Windows 2000 at least).
575 * ega80woa.fon=ega80850.fon
576 * ega40woa.fon=ega40850.fon
577 * cga80woa.fon=cga80850.fon
578 * cga40woa.fon=cga40850.fon
581 /* These are all structures needed for the GSUB table */
583 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
584 #define TATEGAKI_LOWER_BOUND 0x02F1
600 GSUB_ScriptRecord ScriptRecord[1];
606 } GSUB_LangSysRecord;
611 GSUB_LangSysRecord LangSysRecord[1];
615 WORD LookupOrder; /* Reserved */
616 WORD ReqFeatureIndex;
618 WORD FeatureIndex[1];
624 } GSUB_FeatureRecord;
628 GSUB_FeatureRecord FeatureRecord[1];
632 WORD FeatureParams; /* Reserved */
634 WORD LookupListIndex[1];
653 } GSUB_CoverageFormat1;
658 WORD StartCoverageIndex;
664 GSUB_RangeRecord RangeRecord[1];
665 } GSUB_CoverageFormat2;
668 WORD SubstFormat; /* = 1 */
671 } GSUB_SingleSubstFormat1;
674 WORD SubstFormat; /* = 2 */
678 }GSUB_SingleSubstFormat2;
680 #ifdef HAVE_CARBON_CARBON_H
681 static char *find_cache_dir(void)
685 static char cached_path[MAX_PATH];
686 static const char *wine = "/Wine", *fonts = "/Fonts";
688 if(*cached_path) return cached_path;
690 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
693 WARN("can't create cached data folder\n");
696 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
699 WARN("can't create cached data path\n");
703 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
705 ERR("Could not create full path\n");
709 strcat(cached_path, wine);
711 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
713 WARN("Couldn't mkdir %s\n", cached_path);
717 strcat(cached_path, fonts);
718 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
720 WARN("Couldn't mkdir %s\n", cached_path);
727 /******************************************************************
730 * Extracts individual TrueType font files from a Mac suitcase font
731 * and saves them into the user's caches directory (see
733 * Returns a NULL terminated array of filenames.
735 * We do this because they are apps that try to read ttf files
736 * themselves and they don't like Mac suitcase files.
738 static char **expand_mac_font(const char *path)
745 const char *filename;
749 unsigned int size, max_size;
752 TRACE("path %s\n", path);
754 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
757 WARN("failed to get ref\n");
761 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
764 TRACE("no data fork, so trying resource fork\n");
765 res_ref = FSOpenResFile(&ref, fsRdPerm);
768 TRACE("unable to open resource fork\n");
775 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
778 CloseResFile(res_ref);
782 out_dir = find_cache_dir();
784 filename = strrchr(path, '/');
785 if(!filename) filename = path;
788 /* output filename has the form out_dir/filename_%04x.ttf */
789 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
796 unsigned short *num_faces_ptr, num_faces, face;
799 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
801 fond = Get1IndResource(fond_res, idx);
803 TRACE("got fond resource %d\n", idx);
806 fam_rec = *(FamRec**)fond;
807 num_faces_ptr = (unsigned short *)(fam_rec + 1);
808 num_faces = GET_BE_WORD(*num_faces_ptr);
810 assoc = (AsscEntry*)(num_faces_ptr + 1);
811 TRACE("num faces %04x\n", num_faces);
812 for(face = 0; face < num_faces; face++, assoc++)
815 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
816 unsigned short size, font_id;
819 size = GET_BE_WORD(assoc->fontSize);
820 font_id = GET_BE_WORD(assoc->fontID);
823 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
827 TRACE("trying to load sfnt id %04x\n", font_id);
828 sfnt = GetResource(sfnt_res, font_id);
831 TRACE("can't get sfnt resource %04x\n", font_id);
835 output = HeapAlloc(GetProcessHeap(), 0, output_len);
840 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
842 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
843 if(fd != -1 || errno == EEXIST)
847 unsigned char *sfnt_data;
850 sfnt_data = *(unsigned char**)sfnt;
851 write(fd, sfnt_data, GetHandleSize(sfnt));
855 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
858 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
860 ret.array[ret.size++] = output;
864 WARN("unable to create %s\n", output);
865 HeapFree(GetProcessHeap(), 0, output);
868 ReleaseResource(sfnt);
871 ReleaseResource(fond);
874 CloseResFile(res_ref);
879 #endif /* HAVE_CARBON_CARBON_H */
881 static inline BOOL is_win9x(void)
883 return GetVersion() & 0x80000000;
886 This function builds an FT_Fixed from a double. It fails if the absolute
887 value of the float number is greater than 32768.
889 static inline FT_Fixed FT_FixedFromFloat(double f)
895 This function builds an FT_Fixed from a FIXED. It simply put f.value
896 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
898 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
900 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
903 static BOOL is_hinting_enabled(void)
905 static int enabled = -1;
909 /* Use the >= 2.2.0 function if available */
910 if (pFT_Get_TrueType_Engine_Type)
912 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
913 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
915 #ifdef FT_DRIVER_HAS_HINTER
918 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
919 FT_Module mod = pFT_Get_Module(library, "truetype");
920 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
923 else enabled = FALSE;
924 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
929 static BOOL is_subpixel_rendering_enabled( void )
931 #ifdef HAVE_FREETYPE_FTLCDFIL_H
932 static int enabled = -1;
935 enabled = (pFT_Library_SetLcdFilter &&
936 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
937 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
946 static const struct list *get_face_list_from_family(const Family *family)
948 if (!list_empty(&family->faces))
949 return &family->faces;
951 return family->replacement;
954 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
960 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
962 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
964 const struct list *face_list;
965 if(face_name && strcmpiW(face_name, family->FamilyName))
967 face_list = get_face_list_from_family(family);
968 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
972 file = strrchrW(face->file, '/');
977 if(strcmpiW(file, file_name)) continue;
985 static Family *find_family_from_name(const WCHAR *name)
989 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
991 if(!strcmpiW(family->FamilyName, name))
998 static Family *find_family_from_any_name(const WCHAR *name)
1002 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1004 if(!strcmpiW(family->FamilyName, name))
1006 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1013 static void DumpSubstList(void)
1017 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1019 if(psub->from.charset != -1 || psub->to.charset != -1)
1020 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1021 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1023 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1024 debugstr_w(psub->to.name));
1029 static LPWSTR strdupW(LPCWSTR p)
1032 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1033 ret = HeapAlloc(GetProcessHeap(), 0, len);
1034 memcpy(ret, p, len);
1038 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1043 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1045 if(!strcmpiW(element->from.name, from_name) &&
1046 (element->from.charset == from_charset ||
1047 element->from.charset == -1))
1054 #define ADD_FONT_SUBST_FORCE 1
1056 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1058 FontSubst *from_exist, *to_exist;
1060 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1062 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1064 list_remove(&from_exist->entry);
1065 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1066 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1067 HeapFree(GetProcessHeap(), 0, from_exist);
1073 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1077 HeapFree(GetProcessHeap(), 0, subst->to.name);
1078 subst->to.name = strdupW(to_exist->to.name);
1081 list_add_tail(subst_list, &subst->entry);
1086 HeapFree(GetProcessHeap(), 0, subst->from.name);
1087 HeapFree(GetProcessHeap(), 0, subst->to.name);
1088 HeapFree(GetProcessHeap(), 0, subst);
1092 static WCHAR *towstr(UINT cp, const char *str)
1097 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1098 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1099 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1103 static char *strWtoA(UINT cp, const WCHAR *str)
1105 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1106 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1107 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1111 static void split_subst_info(NameCs *nc, LPSTR str)
1113 CHAR *p = strrchr(str, ',');
1117 nc->charset = strtol(p+1, NULL, 10);
1120 nc->name = towstr(CP_ACP, str);
1123 static void LoadSubstList(void)
1127 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1131 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1132 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1133 &hkey) == ERROR_SUCCESS) {
1135 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1136 &valuelen, &datalen, NULL, NULL);
1138 valuelen++; /* returned value doesn't include room for '\0' */
1139 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1140 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1144 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1145 &dlen) == ERROR_SUCCESS) {
1146 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1148 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1149 split_subst_info(&psub->from, value);
1150 split_subst_info(&psub->to, data);
1152 /* Win 2000 doesn't allow mapping between different charsets
1153 or mapping of DEFAULT_CHARSET */
1154 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1155 psub->to.charset == DEFAULT_CHARSET) {
1156 HeapFree(GetProcessHeap(), 0, psub->to.name);
1157 HeapFree(GetProcessHeap(), 0, psub->from.name);
1158 HeapFree(GetProcessHeap(), 0, psub);
1160 add_font_subst(&font_subst_list, psub, 0);
1162 /* reset dlen and vlen */
1166 HeapFree(GetProcessHeap(), 0, data);
1167 HeapFree(GetProcessHeap(), 0, value);
1173 /*****************************************************************
1174 * get_name_table_entry
1176 * Supply the platform, encoding, language and name ids in req
1177 * and if the name exists the function will fill in the string
1178 * and string_len members. The string is owned by FreeType so
1179 * don't free it. Returns TRUE if the name is found else FALSE.
1181 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1184 FT_UInt num_names, name_index;
1186 if(FT_IS_SFNT(ft_face))
1188 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1190 for(name_index = 0; name_index < num_names; name_index++)
1192 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1194 if((name.platform_id == req->platform_id) &&
1195 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1196 (name.language_id == req->language_id) &&
1197 (name.name_id == req->name_id))
1199 req->string = name.string;
1200 req->string_len = name.string_len;
1207 req->string_len = 0;
1211 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1216 name.platform_id = TT_PLATFORM_MICROSOFT;
1217 name.language_id = language_id;
1218 name.name_id = name_id;
1220 if(get_name_table_entry(ft_face, &name))
1224 /* String is not nul terminated and string_len is a byte length. */
1225 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1226 for(i = 0; i < name.string_len / 2; i++)
1228 WORD *tmp = (WORD *)&name.string[i * 2];
1229 ret[i] = GET_BE_WORD(*tmp);
1232 TRACE("Got localised name %s\n", debugstr_w(ret));
1238 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1240 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1241 if (f1->scalable) return TRUE;
1242 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1243 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1246 static void release_family( Family *family )
1248 if (--family->refcount) return;
1249 assert( list_empty( &family->faces ));
1250 list_remove( &family->entry );
1251 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1252 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1253 HeapFree( GetProcessHeap(), 0, family );
1256 static void release_face( Face *face )
1258 if (--face->refcount) return;
1261 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1262 list_remove( &face->entry );
1263 release_family( face->family );
1265 HeapFree( GetProcessHeap(), 0, face->file );
1266 HeapFree( GetProcessHeap(), 0, face->StyleName );
1267 HeapFree( GetProcessHeap(), 0, face->FullName );
1268 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1269 HeapFree( GetProcessHeap(), 0, face );
1272 static inline int style_order(const Face *face)
1274 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1282 case NTM_BOLD | NTM_ITALIC:
1285 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1286 debugstr_w(face->family->FamilyName),
1287 debugstr_w(face->StyleName),
1293 static BOOL insert_face_in_family_list( Face *face, Family *family )
1297 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1299 if (faces_equal( face, cursor ))
1301 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1302 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1303 cursor->font_version, face->font_version);
1305 if (face->font_version <= cursor->font_version)
1307 TRACE("Original font %s is newer so skipping %s\n",
1308 debugstr_w(cursor->file), debugstr_w(face->file));
1313 TRACE("Replacing original %s with %s\n",
1314 debugstr_w(cursor->file), debugstr_w(face->file));
1315 list_add_before( &cursor->entry, &face->entry );
1316 face->family = family;
1319 release_face( cursor );
1324 TRACE("Adding new %s\n", debugstr_w(face->file));
1326 if (style_order( face ) < style_order( cursor )) break;
1329 list_add_before( &cursor->entry, &face->entry );
1330 face->family = family;
1336 /****************************************************************
1337 * NB This function stores the ptrs to the strings to save copying.
1338 * Don't free them after calling.
1340 static Family *create_family( WCHAR *name, WCHAR *english_name )
1342 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1343 family->refcount = 1;
1344 family->FamilyName = name;
1345 family->EnglishName = english_name;
1346 list_init( &family->faces );
1347 family->replacement = &family->faces;
1348 list_add_tail( &font_list, &family->entry );
1353 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1355 DWORD type, size = sizeof(DWORD);
1357 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1358 type != REG_DWORD || size != sizeof(DWORD))
1361 return ERROR_BAD_CONFIGURATION;
1363 return ERROR_SUCCESS;
1366 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1368 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1371 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1373 DWORD needed, strike_index = 0;
1376 /* If we have a File Name key then this is a real font, not just the parent
1377 key of a bunch of non-scalable strikes */
1378 needed = buffer_size;
1379 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1382 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1383 face->cached_enum_data = NULL;
1384 face->family = NULL;
1387 face->file = strdupW( buffer );
1388 face->StyleName = strdupW(face_name);
1390 needed = buffer_size;
1391 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1392 face->FullName = strdupW( buffer );
1394 face->FullName = NULL;
1396 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1397 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1398 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1399 reg_load_dword(hkey_face, face_flags_value, (DWORD*)&face->flags);
1401 needed = sizeof(face->fs);
1402 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1404 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1406 face->scalable = TRUE;
1407 memset(&face->size, 0, sizeof(face->size));
1411 face->scalable = FALSE;
1412 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1413 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1414 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1415 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1416 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1418 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1419 face->size.height, face->size.width, face->size.size >> 6,
1420 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1423 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1424 face->fs.fsCsb[0], face->fs.fsCsb[1],
1425 face->fs.fsUsb[0], face->fs.fsUsb[1],
1426 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1428 if (insert_face_in_family_list(face, family))
1429 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1431 release_face( face );
1434 /* load bitmap strikes */
1436 needed = buffer_size;
1437 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1439 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1441 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1442 RegCloseKey(hkey_strike);
1444 needed = buffer_size;
1448 static void load_font_list_from_cache(HKEY hkey_font_cache)
1450 DWORD size, family_index = 0;
1455 size = sizeof(buffer);
1456 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1458 WCHAR *english_family = NULL;
1459 WCHAR *family_name = strdupW( buffer );
1460 DWORD face_index = 0;
1462 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1463 TRACE("opened family key %s\n", debugstr_w(family_name));
1464 size = sizeof(buffer);
1465 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1466 english_family = strdupW( buffer );
1468 family = create_family(family_name, english_family);
1472 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1473 subst->from.name = strdupW(english_family);
1474 subst->from.charset = -1;
1475 subst->to.name = strdupW(family_name);
1476 subst->to.charset = -1;
1477 add_font_subst(&font_subst_list, subst, 0);
1480 size = sizeof(buffer);
1481 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1483 WCHAR *face_name = strdupW( buffer );
1486 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1488 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1489 RegCloseKey(hkey_face);
1491 HeapFree( GetProcessHeap(), 0, face_name );
1492 size = sizeof(buffer);
1494 RegCloseKey(hkey_family);
1495 release_family( family );
1496 size = sizeof(buffer);
1500 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1503 HKEY hkey_wine_fonts;
1505 /* We don't want to create the fonts key as volatile, so open this first */
1506 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1507 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1508 if(ret != ERROR_SUCCESS)
1510 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1514 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1515 KEY_ALL_ACCESS, NULL, hkey, disposition);
1516 RegCloseKey(hkey_wine_fonts);
1520 static void add_face_to_cache(Face *face)
1522 HKEY hkey_family, hkey_face;
1523 WCHAR *face_key_name;
1525 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1526 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1527 if(face->family->EnglishName)
1528 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1529 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1532 face_key_name = face->StyleName;
1535 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1536 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1537 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1539 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1542 HeapFree(GetProcessHeap(), 0, face_key_name);
1544 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1545 (strlenW(face->file) + 1) * sizeof(WCHAR));
1547 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1548 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1550 reg_save_dword(hkey_face, face_index_value, face->face_index);
1551 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1552 reg_save_dword(hkey_face, face_version_value, face->font_version);
1553 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1555 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1559 reg_save_dword(hkey_face, face_height_value, face->size.height);
1560 reg_save_dword(hkey_face, face_width_value, face->size.width);
1561 reg_save_dword(hkey_face, face_size_value, face->size.size);
1562 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1563 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1564 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1566 RegCloseKey(hkey_face);
1567 RegCloseKey(hkey_family);
1570 static void remove_face_from_cache( Face *face )
1574 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1578 RegDeleteKeyW( hkey_family, face->StyleName );
1582 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1583 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1584 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1585 RegDeleteKeyW( hkey_family, face_key_name );
1586 HeapFree(GetProcessHeap(), 0, face_key_name);
1588 RegCloseKey(hkey_family);
1591 static WCHAR *prepend_at(WCHAR *family)
1598 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1600 strcpyW(str + 1, family);
1601 HeapFree(GetProcessHeap(), 0, family);
1605 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1607 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1608 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1610 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1616 else if (!strcmpiW( *name, *english ))
1618 HeapFree( GetProcessHeap(), 0, *english );
1624 *name = prepend_at( *name );
1625 *english = prepend_at( *english );
1629 static Family *get_family( FT_Face ft_face, BOOL vertical )
1632 WCHAR *name, *english_name;
1634 get_family_names( ft_face, &name, &english_name, vertical );
1636 family = find_family_from_name( name );
1640 family = create_family( name, english_name );
1643 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1644 subst->from.name = strdupW( english_name );
1645 subst->from.charset = -1;
1646 subst->to.name = strdupW( name );
1647 subst->to.charset = -1;
1648 add_font_subst( &font_subst_list, subst, 0 );
1653 HeapFree( GetProcessHeap(), 0, name );
1654 HeapFree( GetProcessHeap(), 0, english_name );
1661 static inline FT_Fixed get_font_version( FT_Face ft_face )
1663 FT_Fixed version = 0;
1666 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1667 if (header) version = header->Font_Revision;
1672 static inline DWORD get_ntm_flags( FT_Face ft_face )
1675 FT_ULong table_size = 0;
1677 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1678 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1679 if (flags == 0) flags = NTM_REGULAR;
1681 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1682 flags |= NTM_PS_OPENTYPE;
1687 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1689 int internal_leading = 0;
1690 FT_WinFNT_HeaderRec winfnt_header;
1692 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1693 internal_leading = winfnt_header.internal_leading;
1695 return internal_leading;
1698 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1703 FT_WinFNT_HeaderRec winfnt_header;
1706 memset( fs, 0, sizeof(*fs) );
1708 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1711 fs->fsUsb[0] = os2->ulUnicodeRange1;
1712 fs->fsUsb[1] = os2->ulUnicodeRange2;
1713 fs->fsUsb[2] = os2->ulUnicodeRange3;
1714 fs->fsUsb[3] = os2->ulUnicodeRange4;
1716 if (os2->version == 0)
1718 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1719 fs->fsCsb[0] = FS_LATIN1;
1721 fs->fsCsb[0] = FS_SYMBOL;
1725 fs->fsCsb[0] = os2->ulCodePageRange1;
1726 fs->fsCsb[1] = os2->ulCodePageRange2;
1731 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1733 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1734 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1735 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1740 if (fs->fsCsb[0] == 0)
1742 /* let's see if we can find any interesting cmaps */
1743 for (i = 0; i < ft_face->num_charmaps; i++)
1745 switch (ft_face->charmaps[i]->encoding)
1747 case FT_ENCODING_UNICODE:
1748 case FT_ENCODING_APPLE_ROMAN:
1749 fs->fsCsb[0] |= FS_LATIN1;
1751 case FT_ENCODING_MS_SYMBOL:
1752 fs->fsCsb[0] |= FS_SYMBOL;
1761 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1764 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1765 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1768 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1769 if (!face->StyleName)
1770 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1771 if (!face->StyleName)
1773 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1776 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1777 if (!face->FullName)
1778 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1779 if (flags & ADDFONT_VERTICAL_FONT)
1780 face->FullName = prepend_at( face->FullName );
1784 face->file = towstr( CP_UNIXCP, file );
1785 face->font_data_ptr = NULL;
1786 face->font_data_size = 0;
1791 face->font_data_ptr = font_data_ptr;
1792 face->font_data_size = font_data_size;
1795 face->face_index = face_index;
1796 get_fontsig( ft_face, &face->fs );
1797 face->ntmFlags = get_ntm_flags( ft_face );
1798 face->font_version = get_font_version( ft_face );
1800 if (FT_IS_SCALABLE( ft_face ))
1802 memset( &face->size, 0, sizeof(face->size) );
1803 face->scalable = TRUE;
1807 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1808 size->height, size->width, size->size >> 6,
1809 size->x_ppem >> 6, size->y_ppem >> 6);
1810 face->size.height = size->height;
1811 face->size.width = size->width;
1812 face->size.size = size->size;
1813 face->size.x_ppem = size->x_ppem;
1814 face->size.y_ppem = size->y_ppem;
1815 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1816 face->scalable = FALSE;
1819 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1820 face->flags = flags;
1821 face->family = NULL;
1822 face->cached_enum_data = NULL;
1824 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1825 face->fs.fsCsb[0], face->fs.fsCsb[1],
1826 face->fs.fsUsb[0], face->fs.fsUsb[1],
1827 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1832 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1833 FT_Long face_index, DWORD flags )
1838 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
1839 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
1840 if (insert_face_in_family_list( face, family ))
1842 if (flags & ADDFONT_ADD_TO_CACHE)
1843 add_face_to_cache( face );
1845 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1846 debugstr_w(face->StyleName));
1848 release_face( face );
1849 release_family( family );
1852 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1853 FT_Long face_index, BOOL allow_bitmap )
1861 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1862 err = pFT_New_Face(library, file, face_index, &ft_face);
1866 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1867 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1872 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1876 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1877 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1879 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1883 if (!FT_IS_SFNT( ft_face ))
1885 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1887 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1893 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1894 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1895 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1897 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1898 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1902 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1903 we don't want to load these. */
1904 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1908 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1910 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1916 if (!ft_face->family_name || !ft_face->style_name)
1918 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1924 pFT_Done_Face( ft_face );
1928 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1931 FT_Long face_index = 0, num_faces;
1934 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1935 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1937 #ifdef HAVE_CARBON_CARBON_H
1940 char **mac_list = expand_mac_font(file);
1943 BOOL had_one = FALSE;
1945 for(cursor = mac_list; *cursor; cursor++)
1948 AddFontToList(*cursor, NULL, 0, flags);
1949 HeapFree(GetProcessHeap(), 0, *cursor);
1951 HeapFree(GetProcessHeap(), 0, mac_list);
1956 #endif /* HAVE_CARBON_CARBON_H */
1959 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
1960 if (!ft_face) return 0;
1962 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1964 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1965 pFT_Done_Face(ft_face);
1969 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
1972 if (FT_HAS_VERTICAL(ft_face))
1974 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
1975 flags | ADDFONT_VERTICAL_FONT);
1979 num_faces = ft_face->num_faces;
1980 pFT_Done_Face(ft_face);
1981 } while(num_faces > ++face_index);
1985 static int remove_font_resource( const char *file, DWORD flags )
1987 Family *family, *family_next;
1988 Face *face, *face_next;
1990 struct stat st, st2;
1993 if (stat( file, &st ) == -1) return 0;
1994 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
1997 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
1999 if (!face->file) continue;
2000 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2001 filename = strWtoA( CP_UNIXCP, face->file );
2002 if (!stat( filename, &st2 ) && st.st_dev == st2.st_dev && st.st_ino == st2.st_ino)
2004 TRACE( "removing matching face %s\n", debugstr_w(face->file) );
2005 release_face( face );
2008 HeapFree( GetProcessHeap(), 0, filename );
2010 release_family( family );
2015 static void DumpFontList(void)
2020 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2021 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2022 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2023 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2025 TRACE(" %d", face->size.height);
2032 /***********************************************************
2033 * The replacement list is a way to map an entire font
2034 * family onto another family. For example adding
2036 * [HKCU\Software\Wine\Fonts\Replacements]
2037 * "Wingdings"="Winedings"
2039 * would enumerate the Winedings font both as Winedings and
2040 * Wingdings. However if a real Wingdings font is present the
2041 * replacement does not take place.
2044 static void LoadReplaceList(void)
2047 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2051 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2052 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2054 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2055 &valuelen, &datalen, NULL, NULL);
2057 valuelen++; /* returned value doesn't include room for '\0' */
2058 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2059 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2063 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2064 &dlen) == ERROR_SUCCESS) {
2065 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2066 /* "NewName"="Oldname" */
2067 if(!find_family_from_any_name(value))
2069 Family * const family = find_family_from_any_name(data);
2072 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2073 if (new_family != NULL)
2075 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2076 new_family->FamilyName = strdupW(value);
2077 new_family->EnglishName = NULL;
2078 list_init(&new_family->faces);
2079 new_family->replacement = &family->faces;
2080 list_add_tail(&font_list, &new_family->entry);
2085 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2090 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2092 /* reset dlen and vlen */
2096 HeapFree(GetProcessHeap(), 0, data);
2097 HeapFree(GetProcessHeap(), 0, value);
2102 static const WCHAR *font_links_list[] =
2104 Lucida_Sans_Unicode,
2105 Microsoft_Sans_Serif,
2109 static const struct font_links_defaults_list
2111 /* Keyed off substitution for "MS Shell Dlg" */
2112 const WCHAR *shelldlg;
2113 /* Maximum of four substitutes, plus terminating NULL pointer */
2114 const WCHAR *substitutes[5];
2115 } font_links_defaults_list[] =
2117 /* Non East-Asian */
2118 { Tahoma, /* FIXME unverified ordering */
2119 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2121 /* Below lists are courtesy of
2122 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2126 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2128 /* Chinese Simplified */
2130 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2134 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2136 /* Chinese Traditional */
2138 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2143 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2145 SYSTEM_LINKS *font_link;
2147 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2149 if(!strcmpiW(font_link->font_name, name))
2156 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2167 SYSTEM_LINKS *font_link;
2169 psub = get_font_subst(&font_subst_list, name, -1);
2170 /* Don't store fonts that are only substitutes for other fonts */
2173 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2177 font_link = find_font_link(name);
2178 if (font_link == NULL)
2180 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2181 font_link->font_name = strdupW(name);
2182 list_init(&font_link->links);
2183 list_add_tail(&system_links, &font_link->entry);
2186 memset(&font_link->fs, 0, sizeof font_link->fs);
2187 for (i = 0; values[i] != NULL; i++)
2189 const struct list *face_list;
2190 CHILD_FONT *child_font;
2193 if (!strcmpiW(name,value))
2195 psub = get_font_subst(&font_subst_list, value, -1);
2197 value = psub->to.name;
2198 family = find_family_from_name(value);
2202 /* Use first extant filename for this Family */
2203 face_list = get_face_list_from_family(family);
2204 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2208 file = strrchrW(face->file, '/');
2217 face = find_face_from_filename(file, value);
2220 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2224 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2225 child_font->face = face;
2226 child_font->font = NULL;
2227 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2228 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2229 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2230 child_font->face->face_index);
2231 list_add_tail(&font_link->links, &child_font->entry);
2233 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2239 /*************************************************************
2242 static BOOL init_system_links(void)
2246 DWORD type, max_val, max_data, val_len, data_len, index;
2247 WCHAR *value, *data;
2248 WCHAR *entry, *next;
2249 SYSTEM_LINKS *font_link, *system_font_link;
2250 CHILD_FONT *child_font;
2251 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2252 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2253 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2258 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2260 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2261 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2262 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2263 val_len = max_val + 1;
2264 data_len = max_data;
2266 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2268 psub = get_font_subst(&font_subst_list, value, -1);
2269 /* Don't store fonts that are only substitutes for other fonts */
2272 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2275 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2276 font_link->font_name = strdupW(value);
2277 memset(&font_link->fs, 0, sizeof font_link->fs);
2278 list_init(&font_link->links);
2279 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2282 CHILD_FONT *child_font;
2284 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2286 next = entry + strlenW(entry) + 1;
2288 face_name = strchrW(entry, ',');
2292 while(isspaceW(*face_name))
2295 psub = get_font_subst(&font_subst_list, face_name, -1);
2297 face_name = psub->to.name;
2299 face = find_face_from_filename(entry, face_name);
2302 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2306 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2307 child_font->face = face;
2308 child_font->font = NULL;
2309 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2310 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2311 TRACE("Adding file %s index %ld\n",
2312 debugstr_w(child_font->face->file), child_font->face->face_index);
2313 list_add_tail(&font_link->links, &child_font->entry);
2315 list_add_tail(&system_links, &font_link->entry);
2317 val_len = max_val + 1;
2318 data_len = max_data;
2321 HeapFree(GetProcessHeap(), 0, value);
2322 HeapFree(GetProcessHeap(), 0, data);
2327 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2329 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2333 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2335 const FontSubst *psub2;
2336 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2338 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2340 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2341 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2343 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2344 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2346 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2348 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2354 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2357 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2358 system_font_link->font_name = strdupW(System);
2359 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2360 list_init(&system_font_link->links);
2362 face = find_face_from_filename(tahoma_ttf, Tahoma);
2365 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2366 child_font->face = face;
2367 child_font->font = NULL;
2368 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2369 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2370 TRACE("Found Tahoma in %s index %ld\n",
2371 debugstr_w(child_font->face->file), child_font->face->face_index);
2372 list_add_tail(&system_font_link->links, &child_font->entry);
2374 font_link = find_font_link(Tahoma);
2375 if (font_link != NULL)
2377 CHILD_FONT *font_link_entry;
2378 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2380 CHILD_FONT *new_child;
2381 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2382 new_child->face = font_link_entry->face;
2383 new_child->font = NULL;
2384 new_child->face->refcount++;
2385 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2386 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2387 list_add_tail(&system_font_link->links, &new_child->entry);
2390 list_add_tail(&system_links, &system_font_link->entry);
2394 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2397 struct dirent *dent;
2398 char path[MAX_PATH];
2400 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2402 dir = opendir(dirname);
2404 WARN("Can't open directory %s\n", debugstr_a(dirname));
2407 while((dent = readdir(dir)) != NULL) {
2408 struct stat statbuf;
2410 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2413 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2415 sprintf(path, "%s/%s", dirname, dent->d_name);
2417 if(stat(path, &statbuf) == -1)
2419 WARN("Can't stat %s\n", debugstr_a(path));
2422 if(S_ISDIR(statbuf.st_mode))
2423 ReadFontDir(path, external_fonts);
2426 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2427 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2428 AddFontToList(path, NULL, 0, addfont_flags);
2435 #ifdef SONAME_LIBFONTCONFIG
2437 static BOOL fontconfig_enabled;
2439 static UINT parse_aa_pattern( FcPattern *pattern )
2445 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2446 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2448 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2452 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2453 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2454 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2455 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2456 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2462 static void init_fontconfig(void)
2464 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2468 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2472 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2473 LOAD_FUNCPTR(FcConfigSubstitute);
2474 LOAD_FUNCPTR(FcFontList);
2475 LOAD_FUNCPTR(FcFontSetDestroy);
2476 LOAD_FUNCPTR(FcInit);
2477 LOAD_FUNCPTR(FcObjectSetAdd);
2478 LOAD_FUNCPTR(FcObjectSetCreate);
2479 LOAD_FUNCPTR(FcObjectSetDestroy);
2480 LOAD_FUNCPTR(FcPatternCreate);
2481 LOAD_FUNCPTR(FcPatternDestroy);
2482 LOAD_FUNCPTR(FcPatternGetBool);
2483 LOAD_FUNCPTR(FcPatternGetInteger);
2484 LOAD_FUNCPTR(FcPatternGetString);
2489 FcPattern *pattern = pFcPatternCreate();
2490 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2491 default_aa_flags = parse_aa_pattern( pattern );
2492 pFcPatternDestroy( pattern );
2493 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2494 fontconfig_enabled = TRUE;
2498 static void load_fontconfig_fonts(void)
2507 if (!fontconfig_enabled) return;
2509 pat = pFcPatternCreate();
2510 os = pFcObjectSetCreate();
2511 pFcObjectSetAdd(os, FC_FILE);
2512 pFcObjectSetAdd(os, FC_SCALABLE);
2513 pFcObjectSetAdd(os, FC_ANTIALIAS);
2514 pFcObjectSetAdd(os, FC_RGBA);
2515 fontset = pFcFontList(NULL, pat, os);
2516 if(!fontset) return;
2517 for(i = 0; i < fontset->nfont; i++) {
2521 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2524 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2526 /* We're just interested in OT/TT fonts for now, so this hack just
2527 picks up the scalable fonts without extensions .pf[ab] to save time
2528 loading every other font */
2530 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2532 TRACE("not scalable\n");
2536 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2537 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2539 len = strlen( file );
2540 if(len < 4) continue;
2541 ext = &file[ len - 3 ];
2542 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2543 AddFontToList(file, NULL, 0,
2544 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2546 pFcFontSetDestroy(fontset);
2547 pFcObjectSetDestroy(os);
2548 pFcPatternDestroy(pat);
2551 #elif defined(HAVE_CARBON_CARBON_H)
2553 static void load_mac_font_callback(const void *value, void *context)
2555 CFStringRef pathStr = value;
2559 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2560 path = HeapAlloc(GetProcessHeap(), 0, len);
2561 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2563 TRACE("font file %s\n", path);
2564 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2566 HeapFree(GetProcessHeap(), 0, path);
2569 static void load_mac_fonts(void)
2571 CFStringRef removeDupesKey;
2572 CFBooleanRef removeDupesValue;
2573 CFDictionaryRef options;
2574 CTFontCollectionRef col;
2576 CFMutableSetRef paths;
2579 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2580 removeDupesValue = kCFBooleanTrue;
2581 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2582 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2583 col = CTFontCollectionCreateFromAvailableFonts(options);
2584 if (options) CFRelease(options);
2587 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2591 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2595 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2599 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2602 WARN("CFSetCreateMutable failed\n");
2607 for (i = 0; i < CFArrayGetCount(descs); i++)
2609 CTFontDescriptorRef desc;
2618 desc = CFArrayGetValueAtIndex(descs, i);
2620 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2621 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2622 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2623 if (!font) continue;
2625 atsFont = CTFontGetPlatformFont(font, NULL);
2632 status = ATSFontGetFileReference(atsFont, &fsref);
2634 if (status != noErr) continue;
2636 url = CFURLCreateFromFSRef(NULL, &fsref);
2639 ext = CFURLCopyPathExtension(url);
2642 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2643 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2652 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2654 if (!path) continue;
2656 CFSetAddValue(paths, path);
2662 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2668 static char *get_data_dir_path( LPCWSTR file )
2670 char *unix_name = NULL;
2671 const char *data_dir = wine_get_data_dir();
2673 if (!data_dir) data_dir = wine_get_build_dir();
2677 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2679 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2680 strcpy(unix_name, data_dir);
2681 strcat(unix_name, "/fonts/");
2683 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2688 static BOOL load_font_from_data_dir(LPCWSTR file)
2691 char *unix_name = get_data_dir_path( file );
2695 EnterCriticalSection( &freetype_cs );
2696 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2697 LeaveCriticalSection( &freetype_cs );
2698 HeapFree(GetProcessHeap(), 0, unix_name);
2703 static char *get_winfonts_dir_path(LPCWSTR file)
2705 static const WCHAR slashW[] = {'\\','\0'};
2706 WCHAR windowsdir[MAX_PATH];
2708 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2709 strcatW(windowsdir, fontsW);
2710 strcatW(windowsdir, slashW);
2711 strcatW(windowsdir, file);
2712 return wine_get_unix_file_name( windowsdir );
2715 static void load_system_fonts(void)
2718 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2719 const WCHAR * const *value;
2721 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2724 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2725 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2726 strcatW(windowsdir, fontsW);
2727 for(value = SystemFontValues; *value; value++) {
2728 dlen = sizeof(data);
2729 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2733 sprintfW(pathW, fmtW, windowsdir, data);
2734 if((unixname = wine_get_unix_file_name(pathW))) {
2735 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2736 HeapFree(GetProcessHeap(), 0, unixname);
2739 load_font_from_data_dir(data);
2746 /*************************************************************
2748 * This adds registry entries for any externally loaded fonts
2749 * (fonts from fontconfig or FontDirs). It also deletes entries
2750 * of no longer existing fonts.
2753 static void update_reg_entries(void)
2755 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2761 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2763 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2764 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2765 ERR("Can't create Windows font reg key\n");
2769 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2770 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2771 ERR("Can't create Windows font reg key\n");
2775 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2776 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2777 ERR("Can't create external font reg key\n");
2781 /* enumerate the fonts and add external ones to the two keys */
2783 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2784 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2786 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
2790 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2791 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2792 strcpyW(valueW, face->FullName);
2796 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2797 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2798 strcpyW(valueW, family->FamilyName);
2801 buffer = strWtoA( CP_UNIXCP, face->file );
2802 path = wine_get_dos_file_name( buffer );
2803 HeapFree( GetProcessHeap(), 0, buffer );
2807 else if ((file = strrchrW(face->file, '/')))
2812 len = strlenW(file) + 1;
2813 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2814 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2815 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2817 HeapFree(GetProcessHeap(), 0, path);
2818 HeapFree(GetProcessHeap(), 0, valueW);
2822 if(external_key) RegCloseKey(external_key);
2823 if(win9x_key) RegCloseKey(win9x_key);
2824 if(winnt_key) RegCloseKey(winnt_key);
2828 static void delete_external_font_keys(void)
2830 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2831 DWORD dlen, vlen, datalen, valuelen, i, type;
2835 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2836 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2837 ERR("Can't create Windows font reg key\n");
2841 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2842 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2843 ERR("Can't create Windows font reg key\n");
2847 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2848 ERR("Can't create external font reg key\n");
2852 /* Delete all external fonts added last time */
2854 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2855 &valuelen, &datalen, NULL, NULL);
2856 valuelen++; /* returned value doesn't include room for '\0' */
2857 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2858 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2860 dlen = datalen * sizeof(WCHAR);
2863 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2864 &dlen) == ERROR_SUCCESS) {
2866 RegDeleteValueW(winnt_key, valueW);
2867 RegDeleteValueW(win9x_key, valueW);
2868 /* reset dlen and vlen */
2872 HeapFree(GetProcessHeap(), 0, data);
2873 HeapFree(GetProcessHeap(), 0, valueW);
2875 /* Delete the old external fonts key */
2876 RegCloseKey(external_key);
2877 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2880 if(win9x_key) RegCloseKey(win9x_key);
2881 if(winnt_key) RegCloseKey(winnt_key);
2884 /*************************************************************
2885 * WineEngAddFontResourceEx
2888 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2894 if (ft_handle) /* do it only if we have freetype up and running */
2898 EnterCriticalSection( &freetype_cs );
2900 if((unixname = wine_get_unix_file_name(file)))
2902 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2904 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2905 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2906 HeapFree(GetProcessHeap(), 0, unixname);
2908 if (!ret && !strchrW(file, '\\')) {
2909 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2910 if ((unixname = get_winfonts_dir_path( file )))
2912 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2913 HeapFree(GetProcessHeap(), 0, unixname);
2915 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2916 if (!ret && (unixname = get_data_dir_path( file )))
2918 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2919 HeapFree(GetProcessHeap(), 0, unixname);
2923 LeaveCriticalSection( &freetype_cs );
2928 /*************************************************************
2929 * WineEngAddFontMemResourceEx
2932 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2936 if (ft_handle) /* do it only if we have freetype up and running */
2938 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2940 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2941 memcpy(pFontCopy, pbFont, cbFont);
2943 EnterCriticalSection( &freetype_cs );
2944 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2945 LeaveCriticalSection( &freetype_cs );
2949 TRACE("AddFontToList failed\n");
2950 HeapFree(GetProcessHeap(), 0, pFontCopy);
2953 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2954 * For now return something unique but quite random
2956 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2957 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2964 /*************************************************************
2965 * WineEngRemoveFontResourceEx
2968 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2974 if (ft_handle) /* do it only if we have freetype up and running */
2978 EnterCriticalSection( &freetype_cs );
2980 if ((unixname = wine_get_unix_file_name(file)))
2982 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2984 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2985 ret = remove_font_resource( unixname, addfont_flags );
2986 HeapFree(GetProcessHeap(), 0, unixname);
2988 if (!ret && !strchrW(file, '\\'))
2990 if ((unixname = get_winfonts_dir_path( file )))
2992 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
2993 HeapFree(GetProcessHeap(), 0, unixname);
2995 if (!ret && (unixname = get_data_dir_path( file )))
2997 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
2998 HeapFree(GetProcessHeap(), 0, unixname);
3002 LeaveCriticalSection( &freetype_cs );
3007 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3013 if (!font_file) return NULL;
3015 file_len = strlenW( font_file );
3017 if (font_path && font_path[0])
3019 int path_len = strlenW( font_path );
3020 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3021 if (!fullname) return NULL;
3022 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3023 fullname[path_len] = '\\';
3024 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3028 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3029 if (!len) return NULL;
3030 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3031 if (!fullname) return NULL;
3032 GetFullPathNameW( font_file, len, fullname, NULL );
3035 unix_name = wine_get_unix_file_name( fullname );
3036 HeapFree( GetProcessHeap(), 0, fullname );
3040 #include <pshpack1.h>
3043 WORD num_of_resources;
3047 CHAR dfCopyright[60];
3053 WORD dfInternalLeading;
3054 WORD dfExternalLeading;
3062 BYTE dfPitchAndFamily;
3073 CHAR szFaceName[LF_FACESIZE];
3076 #include <poppack.h>
3078 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3079 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3081 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3083 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3085 WCHAR *name, *english_name;
3087 NEWTEXTMETRICEXW ntm;
3090 if (!ft_face) return FALSE;
3091 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3092 get_family_names( ft_face, &name, &english_name, FALSE );
3093 pFT_Done_Face( ft_face );
3095 GetEnumStructs( face, name, &elf, &ntm, &type );
3096 release_face( face );
3097 HeapFree( GetProcessHeap(), 0, name );
3098 HeapFree( GetProcessHeap(), 0, english_name );
3100 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3102 memset( fd, 0, sizeof(*fd) );
3104 fd->num_of_resources = 1;
3106 fd->dfVersion = 0x200;
3107 fd->dfSize = sizeof(*fd);
3108 strcpy( fd->dfCopyright, "Wine fontdir" );
3109 fd->dfType = 0x4003; /* 0x0080 set if private */
3110 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3112 fd->dfHorizRes = 72;
3113 fd->dfAscent = ntm.ntmTm.tmAscent;
3114 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3115 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3116 fd->dfItalic = ntm.ntmTm.tmItalic;
3117 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3118 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3119 fd->dfWeight = ntm.ntmTm.tmWeight;
3120 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3122 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3123 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3124 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3125 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3126 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3127 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3128 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3129 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3130 fd->dfWidthBytes = 0;
3132 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3134 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3139 #define NE_FFLAGS_LIBMODULE 0x8000
3140 #define NE_OSFLAGS_WINDOWS 0x02
3142 static const char dos_string[0x40] = "This is a TrueType resource file";
3143 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3145 #include <pshpack2.h>
3166 struct ne_typeinfo fontdir_type;
3167 struct ne_nameinfo fontdir_name;
3168 struct ne_typeinfo scalable_type;
3169 struct ne_nameinfo scalable_name;
3171 BYTE fontdir_res_name[8];
3174 #include <poppack.h>
3176 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3180 DWORD size, written;
3182 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3183 char *font_fileA, *last_part, *ext;
3184 IMAGE_DOS_HEADER dos;
3185 IMAGE_OS2_HEADER ne =
3187 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3189 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3190 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3192 struct rsrc_tab rsrc_tab =
3196 { 0, 0, 0x0c50, 0x2c, 0 },
3198 { 0, 0, 0x0c50, 0x8001, 0 },
3200 { 7,'F','O','N','T','D','I','R'}
3203 memset( &dos, 0, sizeof(dos) );
3204 dos.e_magic = IMAGE_DOS_SIGNATURE;
3205 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3207 /* import name is last part\0, resident name is last part without extension
3208 non-resident name is "FONTRES:" + lfFaceName */
3210 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3211 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3212 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3214 last_part = strrchr( font_fileA, '\\' );
3215 if (last_part) last_part++;
3216 else last_part = font_fileA;
3217 import_name_len = strlen( last_part ) + 1;
3219 ext = strchr( last_part, '.' );
3220 if (ext) res_name_len = ext - last_part;
3221 else res_name_len = import_name_len - 1;
3223 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3225 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3226 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3227 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3228 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3230 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3232 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3233 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3234 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3235 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3237 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3238 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3242 HeapFree( GetProcessHeap(), 0, font_fileA );
3246 memcpy( ptr, &dos, sizeof(dos) );
3247 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3248 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3250 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3251 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3253 ptr = start + dos.e_lfanew + ne.ne_restab;
3254 *ptr++ = res_name_len;
3255 memcpy( ptr, last_part, res_name_len );
3257 ptr = start + dos.e_lfanew + ne.ne_imptab;
3258 *ptr++ = import_name_len;
3259 memcpy( ptr, last_part, import_name_len );
3261 ptr = start + ne.ne_nrestab;
3262 *ptr++ = non_res_name_len;
3263 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3264 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3266 ptr = start + (rsrc_tab.scalable_name.off << 4);
3267 memcpy( ptr, font_fileA, font_file_len );
3269 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3270 memcpy( ptr, fontdir, fontdir->dfSize );
3272 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3273 if (file != INVALID_HANDLE_VALUE)
3275 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3277 CloseHandle( file );
3280 HeapFree( GetProcessHeap(), 0, start );
3281 HeapFree( GetProcessHeap(), 0, font_fileA );
3286 /*************************************************************
3287 * WineEngCreateScalableFontResource
3290 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3291 LPCWSTR font_file, LPCWSTR font_path )
3293 char *unix_name = get_ttf_file_name( font_file, font_path );
3294 struct fontdir fontdir;
3297 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3298 SetLastError( ERROR_INVALID_PARAMETER );
3301 if (hidden) fontdir.dfType |= 0x80;
3302 ret = create_fot( resource, font_file, &fontdir );
3305 HeapFree( GetProcessHeap(), 0, unix_name );
3309 static const struct nls_update_font_list
3311 UINT ansi_cp, oem_cp;
3312 const char *oem, *fixed, *system;
3313 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3314 /* these are for font substitutes */
3315 const char *shelldlg, *tmsrmn;
3316 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3320 const char *from, *to;
3321 } arial_0, courier_new_0, times_new_roman_0;
3322 } nls_update_font_list[] =
3324 /* Latin 1 (United States) */
3325 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3326 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3327 "Tahoma","Times New Roman",
3328 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3331 /* Latin 1 (Multilingual) */
3332 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3333 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3334 "Tahoma","Times New Roman", /* FIXME unverified */
3335 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3338 /* Eastern Europe */
3339 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3340 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3341 "Tahoma","Times New Roman", /* FIXME unverified */
3342 "Fixedsys,238", "System,238",
3343 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3344 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3345 { "Arial CE,0", "Arial,238" },
3346 { "Courier New CE,0", "Courier New,238" },
3347 { "Times New Roman CE,0", "Times New Roman,238" }
3350 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3351 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3352 "Tahoma","Times New Roman", /* FIXME unverified */
3353 "Fixedsys,204", "System,204",
3354 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3355 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3356 { "Arial Cyr,0", "Arial,204" },
3357 { "Courier New Cyr,0", "Courier New,204" },
3358 { "Times New Roman Cyr,0", "Times New Roman,204" }
3361 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3362 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3363 "Tahoma","Times New Roman", /* FIXME unverified */
3364 "Fixedsys,161", "System,161",
3365 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3366 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3367 { "Arial Greek,0", "Arial,161" },
3368 { "Courier New Greek,0", "Courier New,161" },
3369 { "Times New Roman Greek,0", "Times New Roman,161" }
3372 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3373 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3374 "Tahoma","Times New Roman", /* FIXME unverified */
3375 "Fixedsys,162", "System,162",
3376 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3377 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3378 { "Arial Tur,0", "Arial,162" },
3379 { "Courier New Tur,0", "Courier New,162" },
3380 { "Times New Roman Tur,0", "Times New Roman,162" }
3383 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3384 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3385 "Tahoma","Times New Roman", /* FIXME unverified */
3386 "Fixedsys,177", "System,177",
3387 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3388 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3392 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3393 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3394 "Tahoma","Times New Roman", /* FIXME unverified */
3395 "Fixedsys,178", "System,178",
3396 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3397 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3401 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3402 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3403 "Tahoma","Times New Roman", /* FIXME unverified */
3404 "Fixedsys,186", "System,186",
3405 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3406 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3407 { "Arial Baltic,0", "Arial,186" },
3408 { "Courier New Baltic,0", "Courier New,186" },
3409 { "Times New Roman Baltic,0", "Times New Roman,186" }
3412 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3413 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3414 "Tahoma","Times New Roman", /* FIXME unverified */
3415 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3419 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3420 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3421 "Tahoma","Times New Roman", /* FIXME unverified */
3422 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3426 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3427 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3428 "MS UI Gothic","MS Serif",
3429 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3432 /* Chinese Simplified */
3433 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3434 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3435 "SimSun", "NSimSun",
3436 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3440 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3441 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3443 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3446 /* Chinese Traditional */
3447 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3448 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3449 "PMingLiU", "MingLiU",
3450 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3455 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3457 return ( ansi_cp == 932 /* CP932 for Japanese */
3458 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3459 || ansi_cp == 949 /* CP949 for Korean */
3460 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3463 static inline HKEY create_fonts_NT_registry_key(void)
3467 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3468 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3472 static inline HKEY create_fonts_9x_registry_key(void)
3476 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3477 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3481 static inline HKEY create_config_fonts_registry_key(void)
3485 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3486 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3490 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3492 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3494 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3495 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3496 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3497 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3500 static void set_value_key(HKEY hkey, const char *name, const char *value)
3503 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3505 RegDeleteValueA(hkey, name);
3508 static void update_font_info(void)
3510 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3511 char buf[40], cpbuf[40];
3514 UINT i, ansi_cp = 0, oem_cp = 0;
3515 DWORD screen_dpi = 96, font_dpi = 0;
3518 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3519 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3520 &hkey) == ERROR_SUCCESS)
3522 reg_load_dword(hkey, logpixels, &screen_dpi);
3526 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3529 reg_load_dword(hkey, logpixels, &font_dpi);
3531 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3532 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3533 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3534 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3535 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3537 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3538 if (is_dbcs_ansi_cp(ansi_cp))
3539 use_default_fallback = TRUE;
3542 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3544 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3549 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3550 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3552 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3553 ansi_cp, oem_cp, screen_dpi);
3555 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3556 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3559 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3563 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3564 nls_update_font_list[i].oem_cp == oem_cp)
3566 hkey = create_config_fonts_registry_key();
3567 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3568 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3569 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3572 hkey = create_fonts_NT_registry_key();
3573 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3576 hkey = create_fonts_9x_registry_key();
3577 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3580 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3582 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3583 strlen(nls_update_font_list[i].shelldlg)+1);
3584 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3585 strlen(nls_update_font_list[i].tmsrmn)+1);
3587 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3588 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3589 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3590 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3591 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3592 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3593 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3594 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3596 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3597 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3598 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3606 /* Delete the FontSubstitutes from other locales */
3607 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3609 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3610 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3611 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3617 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3620 static BOOL init_freetype(void)
3622 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3625 "Wine cannot find the FreeType font library. To enable Wine to\n"
3626 "use TrueType fonts please install a version of FreeType greater than\n"
3627 "or equal to 2.0.5.\n"
3628 "http://www.freetype.org\n");
3632 #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;}
3634 LOAD_FUNCPTR(FT_Done_Face)
3635 LOAD_FUNCPTR(FT_Get_Char_Index)
3636 LOAD_FUNCPTR(FT_Get_First_Char)
3637 LOAD_FUNCPTR(FT_Get_Module)
3638 LOAD_FUNCPTR(FT_Get_Next_Char)
3639 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3640 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3641 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3642 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3643 LOAD_FUNCPTR(FT_Init_FreeType)
3644 LOAD_FUNCPTR(FT_Library_Version)
3645 LOAD_FUNCPTR(FT_Load_Glyph)
3646 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3647 LOAD_FUNCPTR(FT_Matrix_Multiply)
3648 #ifndef FT_MULFIX_INLINED
3649 LOAD_FUNCPTR(FT_MulFix)
3651 LOAD_FUNCPTR(FT_New_Face)
3652 LOAD_FUNCPTR(FT_New_Memory_Face)
3653 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3654 LOAD_FUNCPTR(FT_Outline_Transform)
3655 LOAD_FUNCPTR(FT_Outline_Translate)
3656 LOAD_FUNCPTR(FT_Render_Glyph)
3657 LOAD_FUNCPTR(FT_Select_Charmap)
3658 LOAD_FUNCPTR(FT_Set_Charmap)
3659 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3660 LOAD_FUNCPTR(FT_Vector_Transform)
3661 LOAD_FUNCPTR(FT_Vector_Unit)
3663 /* Don't warn if these ones are missing */
3664 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3665 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3666 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3669 if(pFT_Init_FreeType(&library) != 0) {
3670 ERR("Can't init FreeType library\n");
3671 wine_dlclose(ft_handle, NULL, 0);
3675 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3677 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3678 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3679 ((FT_Version.minor << 8) & 0x00ff00) |
3680 ((FT_Version.patch ) & 0x0000ff);
3682 font_driver = &freetype_funcs;
3687 "Wine cannot find certain functions that it needs inside the FreeType\n"
3688 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3689 "FreeType to at least version 2.1.4.\n"
3690 "http://www.freetype.org\n");
3691 wine_dlclose(ft_handle, NULL, 0);
3696 static void init_font_list(void)
3698 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3699 static const WCHAR pathW[] = {'P','a','t','h',0};
3701 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3702 WCHAR windowsdir[MAX_PATH];
3704 const char *data_dir;
3706 delete_external_font_keys();
3708 /* load the system bitmap fonts */
3709 load_system_fonts();
3711 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3712 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3713 strcatW(windowsdir, fontsW);
3714 if((unixname = wine_get_unix_file_name(windowsdir)))
3716 ReadFontDir(unixname, FALSE);
3717 HeapFree(GetProcessHeap(), 0, unixname);
3720 /* load the system truetype fonts */
3721 data_dir = wine_get_data_dir();
3722 if (!data_dir) data_dir = wine_get_build_dir();
3723 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3725 strcpy(unixname, data_dir);
3726 strcat(unixname, "/fonts/");
3727 ReadFontDir(unixname, TRUE);
3728 HeapFree(GetProcessHeap(), 0, unixname);
3731 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3732 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3733 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3735 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3736 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3737 &hkey) == ERROR_SUCCESS)
3739 LPWSTR data, valueW;
3740 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3741 &valuelen, &datalen, NULL, NULL);
3743 valuelen++; /* returned value doesn't include room for '\0' */
3744 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3745 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3748 dlen = datalen * sizeof(WCHAR);
3750 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3751 &dlen) == ERROR_SUCCESS)
3753 if(data[0] && (data[1] == ':'))
3755 if((unixname = wine_get_unix_file_name(data)))
3757 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3758 HeapFree(GetProcessHeap(), 0, unixname);
3761 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3763 WCHAR pathW[MAX_PATH];
3764 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3767 sprintfW(pathW, fmtW, windowsdir, data);
3768 if((unixname = wine_get_unix_file_name(pathW)))
3770 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3771 HeapFree(GetProcessHeap(), 0, unixname);
3774 load_font_from_data_dir(data);
3776 /* reset dlen and vlen */
3781 HeapFree(GetProcessHeap(), 0, data);
3782 HeapFree(GetProcessHeap(), 0, valueW);
3786 #ifdef SONAME_LIBFONTCONFIG
3787 load_fontconfig_fonts();
3788 #elif defined(HAVE_CARBON_CARBON_H)
3792 /* then look in any directories that we've specified in the config file */
3793 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3794 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3800 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3802 len += sizeof(WCHAR);
3803 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3804 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3806 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3807 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3808 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3809 TRACE( "got font path %s\n", debugstr_a(valueA) );
3814 LPSTR next = strchr( ptr, ':' );
3815 if (next) *next++ = 0;
3816 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3817 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3819 strcpy( unixname, home );
3820 strcat( unixname, ptr + 1 );
3821 ReadFontDir( unixname, TRUE );
3822 HeapFree( GetProcessHeap(), 0, unixname );
3825 ReadFontDir( ptr, TRUE );
3828 HeapFree( GetProcessHeap(), 0, valueA );
3830 HeapFree( GetProcessHeap(), 0, valueW );
3836 static BOOL move_to_front(const WCHAR *name)
3838 Family *family, *cursor2;
3839 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3841 if(!strcmpiW(family->FamilyName, name))
3843 list_remove(&family->entry);
3844 list_add_head(&font_list, &family->entry);
3851 static BOOL set_default(const WCHAR **name_list)
3855 if (move_to_front(*name_list)) return TRUE;
3862 static void reorder_font_list(void)
3864 set_default( default_serif_list );
3865 set_default( default_fixed_list );
3866 set_default( default_sans_list );
3869 /*************************************************************
3872 * Initialize FreeType library and create a list of available faces
3874 BOOL WineEngInit(void)
3879 /* update locale dependent font info in registry */
3882 if(!init_freetype()) return FALSE;
3884 #ifdef SONAME_LIBFONTCONFIG
3888 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3890 ERR("Failed to create font mutex\n");
3893 WaitForSingleObject(font_mutex, INFINITE);
3895 create_font_cache_key(&hkey_font_cache, &disposition);
3897 if(disposition == REG_CREATED_NEW_KEY)
3900 load_font_list_from_cache(hkey_font_cache);
3902 reorder_font_list();
3909 if(disposition == REG_CREATED_NEW_KEY)
3910 update_reg_entries();
3912 init_system_links();
3914 ReleaseMutex(font_mutex);
3919 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3922 TT_HoriHeader *pHori;
3926 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3927 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3929 if(height == 0) height = 16;
3931 /* Calc. height of EM square:
3933 * For +ve lfHeight we have
3934 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3935 * Re-arranging gives:
3936 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3938 * For -ve lfHeight we have
3940 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3941 * with il = winAscent + winDescent - units_per_em]
3946 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3947 ppem = MulDiv(ft_face->units_per_EM, height,
3948 pHori->Ascender - pHori->Descender);
3950 ppem = MulDiv(ft_face->units_per_EM, height,
3951 pOS2->usWinAscent + pOS2->usWinDescent);
3959 static struct font_mapping *map_font_file( const char *name )
3961 struct font_mapping *mapping;
3965 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3966 if (fstat( fd, &st ) == -1) goto error;
3968 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3970 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3972 mapping->refcount++;
3977 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3980 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3983 if (mapping->data == MAP_FAILED)
3985 HeapFree( GetProcessHeap(), 0, mapping );
3988 mapping->refcount = 1;
3989 mapping->dev = st.st_dev;
3990 mapping->ino = st.st_ino;
3991 mapping->size = st.st_size;
3992 list_add_tail( &mappings_list, &mapping->entry );
4000 static void unmap_font_file( struct font_mapping *mapping )
4002 if (!--mapping->refcount)
4004 list_remove( &mapping->entry );
4005 munmap( mapping->data, mapping->size );
4006 HeapFree( GetProcessHeap(), 0, mapping );
4010 static LONG load_VDMX(GdiFont*, LONG);
4012 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4019 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4023 char *filename = strWtoA( CP_UNIXCP, face->file );
4024 font->mapping = map_font_file( filename );
4025 HeapFree( GetProcessHeap(), 0, filename );
4028 WARN("failed to map %s\n", debugstr_w(face->file));
4031 data_ptr = font->mapping->data;
4032 data_size = font->mapping->size;
4036 data_ptr = face->font_data_ptr;
4037 data_size = face->font_data_size;
4040 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4042 ERR("FT_New_Face rets %d\n", err);
4046 /* set it here, as load_VDMX needs it */
4047 font->ft_face = ft_face;
4049 if(FT_IS_SCALABLE(ft_face)) {
4050 /* load the VDMX table if we have one */
4051 font->ppem = load_VDMX(font, height);
4053 font->ppem = calc_ppem_for_height(ft_face, height);
4054 TRACE("height %d => ppem %d\n", height, font->ppem);
4056 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4057 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4059 font->ppem = height;
4060 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4061 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4067 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4069 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4070 a single face with the requested charset. The idea is to check if
4071 the selected font supports the current ANSI codepage, if it does
4072 return the corresponding charset, else return the first charset */
4075 int acp = GetACP(), i;
4079 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4081 const SYSTEM_LINKS *font_link;
4083 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4084 return csi.ciCharset;
4086 font_link = find_font_link(family_name);
4087 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4088 return csi.ciCharset;
4091 for(i = 0; i < 32; i++) {
4093 if(face->fs.fsCsb[0] & fs0) {
4094 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4096 return csi.ciCharset;
4099 FIXME("TCI failing on %x\n", fs0);
4103 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4104 face->fs.fsCsb[0], debugstr_w(face->file));
4106 return DEFAULT_CHARSET;
4109 static GdiFont *alloc_font(void)
4111 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4114 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4115 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4117 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4118 ret->total_kern_pairs = (DWORD)-1;
4119 ret->kern_pairs = NULL;
4120 list_init(&ret->child_fonts);
4124 static void free_font(GdiFont *font)
4126 CHILD_FONT *child, *child_next;
4129 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4131 list_remove(&child->entry);
4133 free_font(child->font);
4134 release_face( child->face );
4135 HeapFree(GetProcessHeap(), 0, child);
4138 if (font->ft_face) pFT_Done_Face(font->ft_face);
4139 if (font->mapping) unmap_font_file( font->mapping );
4140 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4141 HeapFree(GetProcessHeap(), 0, font->potm);
4142 HeapFree(GetProcessHeap(), 0, font->name);
4143 for (i = 0; i < font->gmsize; i++)
4144 HeapFree(GetProcessHeap(),0,font->gm[i]);
4145 HeapFree(GetProcessHeap(), 0, font->gm);
4146 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4147 HeapFree(GetProcessHeap(), 0, font);
4151 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4153 FT_Face ft_face = font->ft_face;
4157 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4164 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4166 /* make sure value of len is the value freetype says it needs */
4169 FT_ULong needed = 0;
4170 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4171 if( !err && needed < len) len = needed;
4173 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4176 TRACE("Can't find table %c%c%c%c\n",
4177 /* bytes were reversed */
4178 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4179 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4185 /*************************************************************
4188 * load the vdmx entry for the specified height
4191 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4192 ( ( (FT_ULong)_x4 << 24 ) | \
4193 ( (FT_ULong)_x3 << 16 ) | \
4194 ( (FT_ULong)_x2 << 8 ) | \
4197 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4212 static LONG load_VDMX(GdiFont *font, LONG height)
4216 BYTE devXRatio, devYRatio;
4217 USHORT numRecs, numRatios;
4218 DWORD result, offset = -1;
4222 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4224 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4227 /* FIXME: need the real device aspect ratio */
4231 numRecs = GET_BE_WORD(hdr[1]);
4232 numRatios = GET_BE_WORD(hdr[2]);
4234 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4235 for(i = 0; i < numRatios; i++) {
4238 offset = (3 * 2) + (i * sizeof(Ratios));
4239 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4242 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4244 if((ratio.xRatio == 0 &&
4245 ratio.yStartRatio == 0 &&
4246 ratio.yEndRatio == 0) ||
4247 (devXRatio == ratio.xRatio &&
4248 devYRatio >= ratio.yStartRatio &&
4249 devYRatio <= ratio.yEndRatio))
4251 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4252 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4253 offset = GET_BE_WORD(tmp);
4259 FIXME("No suitable ratio found\n");
4263 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4265 BYTE startsz, endsz;
4268 recs = GET_BE_WORD(group.recs);
4269 startsz = group.startsz;
4270 endsz = group.endsz;
4272 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4274 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4275 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4276 if(result == GDI_ERROR) {
4277 FIXME("Failed to retrieve vTable\n");
4282 for(i = 0; i < recs; i++) {
4283 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4284 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4285 ppem = GET_BE_WORD(vTable[i * 3]);
4287 if(yMax + -yMin == height) {
4290 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4293 if(yMax + -yMin > height) {
4296 goto end; /* failed */
4298 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4299 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4300 ppem = GET_BE_WORD(vTable[i * 3]);
4301 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4307 TRACE("ppem not found for height %d\n", height);
4311 HeapFree(GetProcessHeap(), 0, vTable);
4317 static void dump_gdi_font_list(void)
4321 TRACE("---------- Font Cache ----------\n");
4322 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4323 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4324 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4327 static void grab_font( GdiFont *font )
4329 if (!font->refcount++)
4331 list_remove( &font->unused_entry );
4332 unused_font_count--;
4336 static void release_font( GdiFont *font )
4339 if (!--font->refcount)
4341 TRACE( "font %p\n", font );
4343 /* add it to the unused list */
4344 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4345 if (unused_font_count > UNUSED_CACHE_SIZE)
4347 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4348 TRACE( "freeing %p\n", font );
4349 list_remove( &font->entry );
4350 list_remove( &font->unused_entry );
4353 else unused_font_count++;
4355 if (TRACE_ON(font)) dump_gdi_font_list();
4359 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4361 if(font->font_desc.hash != fd->hash) return TRUE;
4362 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4363 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4364 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4365 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4368 static void calc_hash(FONT_DESC *pfd)
4370 DWORD hash = 0, *ptr, two_chars;
4374 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4376 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4378 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4380 pwc = (WCHAR *)&two_chars;
4382 *pwc = toupperW(*pwc);
4384 *pwc = toupperW(*pwc);
4388 hash ^= !pfd->can_use_bitmap;
4393 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4400 fd.can_use_bitmap = can_use_bitmap;
4403 /* try the in-use list */
4404 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4406 if(fontcmp(ret, &fd)) continue;
4407 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4408 list_remove( &ret->entry );
4409 list_add_head( &gdi_font_list, &ret->entry );
4416 static void add_to_cache(GdiFont *font)
4418 static DWORD cache_num = 1;
4420 font->cache_num = cache_num++;
4421 list_add_head(&gdi_font_list, &font->entry);
4422 TRACE( "font %p\n", font );
4425 /*************************************************************
4426 * create_child_font_list
4428 static BOOL create_child_font_list(GdiFont *font)
4431 SYSTEM_LINKS *font_link;
4432 CHILD_FONT *font_link_entry, *new_child;
4436 psub = get_font_subst(&font_subst_list, font->name, -1);
4437 font_name = psub ? psub->to.name : font->name;
4438 font_link = find_font_link(font_name);
4439 if (font_link != NULL)
4441 TRACE("found entry in system list\n");
4442 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4444 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4445 new_child->face = font_link_entry->face;
4446 new_child->font = NULL;
4447 new_child->face->refcount++;
4448 list_add_tail(&font->child_fonts, &new_child->entry);
4449 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4454 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4455 * Sans Serif. This is how asian windows get default fallbacks for fonts
4457 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4458 font->charset != OEM_CHARSET &&
4459 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4461 font_link = find_font_link(szDefaultFallbackLink);
4462 if (font_link != NULL)
4464 TRACE("found entry in default fallback list\n");
4465 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4467 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4468 new_child->face = font_link_entry->face;
4469 new_child->font = NULL;
4470 new_child->face->refcount++;
4471 list_add_tail(&font->child_fonts, &new_child->entry);
4472 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4481 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4483 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4485 if (pFT_Set_Charmap)
4488 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4490 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4492 for (i = 0; i < ft_face->num_charmaps; i++)
4494 if (ft_face->charmaps[i]->encoding == encoding)
4496 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4497 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4499 switch (ft_face->charmaps[i]->platform_id)
4502 cmap_def = ft_face->charmaps[i];
4504 case 0: /* Apple Unicode */
4505 cmap0 = ft_face->charmaps[i];
4507 case 1: /* Macintosh */
4508 cmap1 = ft_face->charmaps[i];
4511 cmap2 = ft_face->charmaps[i];
4513 case 3: /* Microsoft */
4514 cmap3 = ft_face->charmaps[i];
4519 if (cmap3) /* prefer Microsoft cmap table */
4520 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4522 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4524 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4526 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4528 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4530 return ft_err == FT_Err_Ok;
4533 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4537 /*************************************************************
4540 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4541 LPCWSTR output, const DEVMODEW *devmode )
4543 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4545 if (!physdev) return FALSE;
4546 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4551 /*************************************************************
4554 static BOOL freetype_DeleteDC( PHYSDEV dev )
4556 struct freetype_physdev *physdev = get_freetype_dev( dev );
4557 release_font( physdev->font );
4558 HeapFree( GetProcessHeap(), 0, physdev );
4562 static FT_Encoding pick_charmap( FT_Face face, int charset )
4564 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4565 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4566 const FT_Encoding *encs = regular_order;
4568 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4572 if (select_charmap( face, *encs )) break;
4578 #define GASP_GRIDFIT 0x01
4579 #define GASP_DOGRAY 0x02
4580 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4582 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4585 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4586 WORD *alloced = NULL, *ptr = buf;
4587 WORD num_recs, version;
4591 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4592 if (size == GDI_ERROR) return FALSE;
4593 if (size < 4 * sizeof(WORD)) return FALSE;
4594 if (size > sizeof(buf))
4596 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4597 if (!ptr) return FALSE;
4600 get_font_data( font, GASP_TAG, 0, ptr, size );
4602 version = GET_BE_WORD( *ptr++ );
4603 num_recs = GET_BE_WORD( *ptr++ );
4605 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4607 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4613 *flags = GET_BE_WORD( *(ptr + 1) );
4614 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4617 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4621 HeapFree( GetProcessHeap(), 0, alloced );
4625 /*************************************************************
4626 * freetype_SelectFont
4628 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4630 struct freetype_physdev *physdev = get_freetype_dev( dev );
4632 Face *face, *best, *best_bitmap;
4633 Family *family, *last_resort_family;
4634 const struct list *face_list;
4635 INT height, width = 0;
4636 unsigned int score = 0, new_score;
4637 signed int diff = 0, newdiff;
4638 BOOL bd, it, can_use_bitmap, want_vertical;
4642 FontSubst *psub = NULL;
4643 DC *dc = get_dc_ptr( dev->hdc );
4644 const SYSTEM_LINKS *font_link;
4646 if (!hfont) /* notification that the font has been changed by another driver */
4648 release_font( physdev->font );
4649 physdev->font = NULL;
4650 release_dc_ptr( dc );
4654 GetObjectW( hfont, sizeof(lf), &lf );
4655 lf.lfWidth = abs(lf.lfWidth);
4657 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4659 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4660 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4661 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4664 if(dc->GraphicsMode == GM_ADVANCED)
4666 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4667 /* Try to avoid not necessary glyph transformations */
4668 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4670 lf.lfHeight *= fabs(dcmat.eM11);
4671 lf.lfWidth *= fabs(dcmat.eM11);
4672 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4677 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4678 font scaling abilities. */
4679 dcmat.eM11 = dcmat.eM22 = 1.0;
4680 dcmat.eM21 = dcmat.eM12 = 0;
4681 lf.lfOrientation = lf.lfEscapement;
4682 if (dc->vport2WorldValid)
4684 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4685 lf.lfOrientation = -lf.lfOrientation;
4686 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4687 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4691 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4692 dcmat.eM21, dcmat.eM22);
4695 EnterCriticalSection( &freetype_cs );
4697 /* check the cache first */
4698 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4699 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4703 TRACE("not in cache\n");
4706 ret->font_desc.matrix = dcmat;
4707 ret->font_desc.lf = lf;
4708 ret->font_desc.can_use_bitmap = can_use_bitmap;
4709 calc_hash(&ret->font_desc);
4711 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4712 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4713 original value lfCharSet. Note this is a special case for
4714 Symbol and doesn't happen at least for "Wingdings*" */
4716 if(!strcmpiW(lf.lfFaceName, SymbolW))
4717 lf.lfCharSet = SYMBOL_CHARSET;
4719 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4720 switch(lf.lfCharSet) {
4721 case DEFAULT_CHARSET:
4722 csi.fs.fsCsb[0] = 0;
4725 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4726 csi.fs.fsCsb[0] = 0;
4732 if(lf.lfFaceName[0] != '\0') {
4733 CHILD_FONT *font_link_entry;
4734 LPWSTR FaceName = lf.lfFaceName;
4736 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4739 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4740 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4741 if (psub->to.charset != -1)
4742 lf.lfCharSet = psub->to.charset;
4745 /* We want a match on name and charset or just name if
4746 charset was DEFAULT_CHARSET. If the latter then
4747 we fixup the returned charset later in get_nearest_charset
4748 where we'll either use the charset of the current ansi codepage
4749 or if that's unavailable the first charset that the font supports.
4751 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4752 if (!strcmpiW(family->FamilyName, FaceName) ||
4753 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4755 font_link = find_font_link(family->FamilyName);
4756 face_list = get_face_list_from_family(family);
4757 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4758 if (!(face->scalable || can_use_bitmap))
4760 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4762 if (font_link != NULL &&
4763 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4765 if (!csi.fs.fsCsb[0])
4771 /* Search by full face name. */
4772 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4773 face_list = get_face_list_from_family(family);
4774 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4775 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4776 (face->scalable || can_use_bitmap))
4778 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4780 font_link = find_font_link(family->FamilyName);
4781 if (font_link != NULL &&
4782 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4789 * Try check the SystemLink list first for a replacement font.
4790 * We may find good replacements there.
4792 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4794 if(!strcmpiW(font_link->font_name, FaceName) ||
4795 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4797 TRACE("found entry in system list\n");
4798 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4800 const SYSTEM_LINKS *links;
4802 face = font_link_entry->face;
4803 if (!(face->scalable || can_use_bitmap))
4805 family = face->family;
4806 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4808 links = find_font_link(family->FamilyName);
4809 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4816 psub = NULL; /* substitution is no more relevant */
4818 /* If requested charset was DEFAULT_CHARSET then try using charset
4819 corresponding to the current ansi codepage */
4820 if (!csi.fs.fsCsb[0])
4823 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4824 FIXME("TCI failed on codepage %d\n", acp);
4825 csi.fs.fsCsb[0] = 0;
4827 lf.lfCharSet = csi.ciCharset;
4830 want_vertical = (lf.lfFaceName[0] == '@');
4832 /* Face families are in the top 4 bits of lfPitchAndFamily,
4833 so mask with 0xF0 before testing */
4835 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4836 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4837 strcpyW(lf.lfFaceName, defFixed);
4838 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4839 strcpyW(lf.lfFaceName, defSerif);
4840 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4841 strcpyW(lf.lfFaceName, defSans);
4843 strcpyW(lf.lfFaceName, defSans);
4844 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4845 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4846 font_link = find_font_link(family->FamilyName);
4847 face_list = get_face_list_from_family(family);
4848 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4849 if (!(face->scalable || can_use_bitmap))
4851 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4853 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4859 last_resort_family = NULL;
4860 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4861 font_link = find_font_link(family->FamilyName);
4862 face_list = get_face_list_from_family(family);
4863 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4864 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
4865 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4866 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4869 if(can_use_bitmap && !last_resort_family)
4870 last_resort_family = family;
4875 if(last_resort_family) {
4876 family = last_resort_family;
4877 csi.fs.fsCsb[0] = 0;
4881 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4882 face_list = get_face_list_from_family(family);
4883 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4884 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
4885 csi.fs.fsCsb[0] = 0;
4886 WARN("just using first face for now\n");
4889 if(can_use_bitmap && !last_resort_family)
4890 last_resort_family = family;
4893 if(!last_resort_family) {
4894 FIXME("can't find a single appropriate font - bailing\n");
4900 WARN("could only find a bitmap font - this will probably look awful!\n");
4901 family = last_resort_family;
4902 csi.fs.fsCsb[0] = 0;
4905 it = lf.lfItalic ? 1 : 0;
4906 bd = lf.lfWeight > 550 ? 1 : 0;
4908 height = lf.lfHeight;
4910 face = best = best_bitmap = NULL;
4911 font_link = find_font_link(family->FamilyName);
4912 face_list = get_face_list_from_family(family);
4913 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4915 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4916 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4921 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4922 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4923 new_score = (italic ^ it) + (bold ^ bd);
4924 if(!best || new_score <= score)
4926 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4927 italic, bold, it, bd);
4930 if(best->scalable && score == 0) break;
4934 newdiff = height - (signed int)(best->size.height);
4936 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4937 if(!best_bitmap || new_score < score ||
4938 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4940 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4943 if(score == 0 && diff == 0) break;
4950 face = best->scalable ? best : best_bitmap;
4951 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4952 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4955 height = lf.lfHeight;
4959 if(csi.fs.fsCsb[0]) {
4960 ret->charset = lf.lfCharSet;
4961 ret->codepage = csi.ciACP;
4964 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4966 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4967 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
4969 ret->aveWidth = height ? lf.lfWidth : 0;
4971 if(!face->scalable) {
4972 /* Windows uses integer scaling factors for bitmap fonts */
4973 INT scale, scaled_height;
4974 GdiFont *cachedfont;
4976 /* FIXME: rotation of bitmap fonts is ignored */
4977 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4979 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4980 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4981 dcmat.eM11 = dcmat.eM22 = 1.0;
4982 /* As we changed the matrix, we need to search the cache for the font again,
4983 * otherwise we might explode the cache. */
4984 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4985 TRACE("Found cached font after non-scalable matrix rescale!\n");
4990 calc_hash(&ret->font_desc);
4992 if (height != 0) height = diff;
4993 height += face->size.height;
4995 scale = (height + face->size.height - 1) / face->size.height;
4996 scaled_height = scale * face->size.height;
4997 /* Only jump to the next height if the difference <= 25% original height */
4998 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4999 /* The jump between unscaled and doubled is delayed by 1 */
5000 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5001 ret->scale_y = scale;
5003 width = face->size.x_ppem >> 6;
5004 height = face->size.y_ppem >> 6;
5008 TRACE("font scale y: %f\n", ret->scale_y);
5010 ret->ft_face = OpenFontFace(ret, face, width, height);
5019 ret->ntmFlags = face->ntmFlags;
5021 pick_charmap( ret->ft_face, ret->charset );
5023 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5024 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5025 ret->underline = lf.lfUnderline ? 0xff : 0;
5026 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5027 create_child_font_list(ret);
5029 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5031 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5032 if (length != GDI_ERROR)
5034 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5035 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5036 TRACE("Loaded GSUB table of %i bytes\n",length);
5039 ret->aa_flags = HIWORD( face->flags );
5041 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5047 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5049 switch (lf.lfQuality)
5051 case NONANTIALIASED_QUALITY:
5052 case ANTIALIASED_QUALITY:
5053 next->funcs->pSelectFont( dev, hfont, aa_flags );
5055 case CLEARTYPE_QUALITY:
5056 case CLEARTYPE_NATURAL_QUALITY:
5058 if (!*aa_flags) *aa_flags = ret->aa_flags;
5059 next->funcs->pSelectFont( dev, hfont, aa_flags );
5061 /* fixup the antialiasing flags for that font */
5064 case WINE_GGO_HRGB_BITMAP:
5065 case WINE_GGO_HBGR_BITMAP:
5066 case WINE_GGO_VRGB_BITMAP:
5067 case WINE_GGO_VBGR_BITMAP:
5068 if (is_subpixel_rendering_enabled()) break;
5069 *aa_flags = GGO_GRAY4_BITMAP;
5071 case GGO_GRAY2_BITMAP:
5072 case GGO_GRAY4_BITMAP:
5073 case GGO_GRAY8_BITMAP:
5074 case WINE_GGO_GRAY16_BITMAP:
5075 if (is_hinting_enabled())
5078 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5080 TRACE( "font %s %d aa disabled by GASP\n",
5081 debugstr_w(lf.lfFaceName), lf.lfHeight );
5082 *aa_flags = GGO_BITMAP;
5087 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5088 release_font( physdev->font );
5089 physdev->font = ret;
5091 LeaveCriticalSection( &freetype_cs );
5092 release_dc_ptr( dc );
5093 return ret ? hfont : 0;
5096 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5103 id += IDS_FIRST_SCRIPT;
5104 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5105 if (!rsrc) return 0;
5106 hMem = LoadResource( gdi32_module, rsrc );
5107 if (!hMem) return 0;
5109 p = LockResource( hMem );
5111 while (id--) p += *p + 1;
5113 i = min(LF_FACESIZE - 1, *p);
5114 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5120 /***************************************************
5121 * create_enum_charset_list
5123 * This function creates charset enumeration list because in DEFAULT_CHARSET
5124 * case, the ANSI codepage's charset takes precedence over other charsets.
5125 * This function works as a filter other than DEFAULT_CHARSET case.
5127 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5132 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5133 csi.fs.fsCsb[0] != 0) {
5134 list->element[n].mask = csi.fs.fsCsb[0];
5135 list->element[n].charset = csi.ciCharset;
5136 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5139 else { /* charset is DEFAULT_CHARSET or invalid. */
5143 /* Set the current codepage's charset as the first element. */
5145 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5146 csi.fs.fsCsb[0] != 0) {
5147 list->element[n].mask = csi.fs.fsCsb[0];
5148 list->element[n].charset = csi.ciCharset;
5149 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5150 mask |= csi.fs.fsCsb[0];
5154 /* Fill out left elements. */
5155 for (i = 0; i < 32; i++) {
5157 fs.fsCsb[0] = 1L << i;
5159 if (fs.fsCsb[0] & mask)
5160 continue; /* skip, already added. */
5161 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5162 continue; /* skip, this is an invalid fsCsb bit. */
5164 list->element[n].mask = fs.fsCsb[0];
5165 list->element[n].charset = csi.ciCharset;
5166 load_script_name( i, list->element[n].name );
5167 mask |= fs.fsCsb[0];
5171 /* add catch all mask for remaining bits */
5174 list->element[n].mask = ~mask;
5175 list->element[n].charset = DEFAULT_CHARSET;
5176 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5185 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5186 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5191 if (face->cached_enum_data)
5194 *pelf = face->cached_enum_data->elf;
5195 *pntm = face->cached_enum_data->ntm;
5196 *ptype = face->cached_enum_data->type;
5200 font = alloc_font();
5202 if(face->scalable) {
5206 height = face->size.y_ppem >> 6;
5207 width = face->size.x_ppem >> 6;
5209 font->scale_y = 1.0;
5211 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5217 font->name = strdupW( family_name );
5218 font->ntmFlags = face->ntmFlags;
5220 if (get_outline_text_metrics(font))
5222 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5224 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5225 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5226 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5228 lstrcpynW(pelf->elfLogFont.lfFaceName,
5229 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5231 lstrcpynW(pelf->elfFullName,
5232 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5234 lstrcpynW(pelf->elfStyle,
5235 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5240 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5242 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5243 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5244 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5246 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5248 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5250 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5251 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5254 pntm->ntmTm.ntmFlags = face->ntmFlags;
5255 pntm->ntmFontSig = face->fs;
5257 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5259 pelf->elfLogFont.lfEscapement = 0;
5260 pelf->elfLogFont.lfOrientation = 0;
5261 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5262 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5263 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5264 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5265 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5266 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5267 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5268 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5269 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5270 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5271 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5274 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5275 *ptype |= TRUETYPE_FONTTYPE;
5276 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5277 *ptype |= DEVICE_FONTTYPE;
5278 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5279 *ptype |= RASTER_FONTTYPE;
5281 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5282 if (face->cached_enum_data)
5284 face->cached_enum_data->elf = *pelf;
5285 face->cached_enum_data->ntm = *pntm;
5286 face->cached_enum_data->type = *ptype;
5292 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5295 const struct list *face_list;
5297 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5299 face_list = get_face_list_from_family(family);
5300 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5301 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5306 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5308 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5310 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5313 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5314 FONTENUMPROCW proc, LPARAM lparam)
5317 NEWTEXTMETRICEXW ntm;
5321 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5322 for(i = 0; i < list->total; i++) {
5323 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5324 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5325 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5326 i = list->total; /* break out of loop after enumeration */
5330 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5331 /* use the DEFAULT_CHARSET case only if no other charset is present */
5332 if (list->element[i].charset == DEFAULT_CHARSET &&
5333 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5334 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5335 strcpyW(elf.elfScript, list->element[i].name);
5336 if (!elf.elfScript[0])
5337 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5339 /* Font Replacement */
5340 if (family != face->family)
5342 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5344 strcpyW(elf.elfFullName, face->FullName);
5346 strcpyW(elf.elfFullName, family->FamilyName);
5348 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5349 debugstr_w(elf.elfLogFont.lfFaceName),
5350 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5351 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5352 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5353 ntm.ntmTm.ntmFlags);
5354 /* release section before callback (FIXME) */
5355 LeaveCriticalSection( &freetype_cs );
5356 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5357 EnterCriticalSection( &freetype_cs );
5362 /*************************************************************
5363 * freetype_EnumFonts
5365 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5369 const struct list *face_list;
5371 struct enum_charset_list enum_charsets;
5375 lf.lfCharSet = DEFAULT_CHARSET;
5376 lf.lfPitchAndFamily = 0;
5377 lf.lfFaceName[0] = 0;
5381 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5383 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5386 EnterCriticalSection( &freetype_cs );
5387 if(plf->lfFaceName[0]) {
5389 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5392 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5393 debugstr_w(psub->to.name));
5395 strcpyW(lf.lfFaceName, psub->to.name);
5399 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5400 if (!family_matches(family, plf)) continue;
5401 face_list = get_face_list_from_family(family);
5402 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5403 if (!face_matches(family->FamilyName, face, plf)) continue;
5404 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5408 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5409 face_list = get_face_list_from_family(family);
5410 face = LIST_ENTRY(list_head(face_list), Face, entry);
5411 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5414 LeaveCriticalSection( &freetype_cs );
5418 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5420 pt->x.value = vec->x >> 6;
5421 pt->x.fract = (vec->x & 0x3f) << 10;
5422 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5423 pt->y.value = vec->y >> 6;
5424 pt->y.fract = (vec->y & 0x3f) << 10;
5425 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5429 /***************************************************
5430 * According to the MSDN documentation on WideCharToMultiByte,
5431 * certain codepages cannot set the default_used parameter.
5432 * This returns TRUE if the codepage can set that parameter, false else
5433 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5435 static BOOL codepage_sets_default_used(UINT codepage)
5449 * GSUB Table handling functions
5452 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5454 const GSUB_CoverageFormat1* cf1;
5458 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5460 int count = GET_BE_WORD(cf1->GlyphCount);
5462 TRACE("Coverage Format 1, %i glyphs\n",count);
5463 for (i = 0; i < count; i++)
5464 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5468 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5470 const GSUB_CoverageFormat2* cf2;
5473 cf2 = (const GSUB_CoverageFormat2*)cf1;
5475 count = GET_BE_WORD(cf2->RangeCount);
5476 TRACE("Coverage Format 2, %i ranges\n",count);
5477 for (i = 0; i < count; i++)
5479 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5481 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5482 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5484 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5485 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5491 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5496 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5498 const GSUB_ScriptList *script;
5499 const GSUB_Script *deflt = NULL;
5501 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5503 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5504 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5506 const GSUB_Script *scr;
5509 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5510 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5512 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5514 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5520 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5524 const GSUB_LangSys *Lang;
5526 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5528 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5530 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5531 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5533 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5536 offset = GET_BE_WORD(script->DefaultLangSys);
5539 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5545 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5548 const GSUB_FeatureList *feature;
5549 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5551 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5552 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5554 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5555 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5557 const GSUB_Feature *feat;
5558 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5565 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5569 const GSUB_LookupList *lookup;
5570 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5572 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5573 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5575 const GSUB_LookupTable *look;
5576 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5577 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5578 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5579 if (GET_BE_WORD(look->LookupType) != 1)
5580 FIXME("We only handle SubType 1\n");
5585 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5587 const GSUB_SingleSubstFormat1 *ssf1;
5588 offset = GET_BE_WORD(look->SubTable[j]);
5589 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5590 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5592 int offset = GET_BE_WORD(ssf1->Coverage);
5593 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5594 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5596 TRACE(" Glyph 0x%x ->",glyph);
5597 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5598 TRACE(" 0x%x\n",glyph);
5603 const GSUB_SingleSubstFormat2 *ssf2;
5607 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5608 offset = GET_BE_WORD(ssf1->Coverage);
5609 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5610 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5611 TRACE(" Coverage index %i\n",index);
5614 TRACE(" Glyph is 0x%x ->",glyph);
5615 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5616 TRACE("0x%x\n",glyph);
5625 static const char* get_opentype_script(const GdiFont *font)
5628 * I am not sure if this is the correct way to generate our script tag
5631 switch (font->charset)
5633 case ANSI_CHARSET: return "latn";
5634 case BALTIC_CHARSET: return "latn"; /* ?? */
5635 case CHINESEBIG5_CHARSET: return "hani";
5636 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5637 case GB2312_CHARSET: return "hani";
5638 case GREEK_CHARSET: return "grek";
5639 case HANGUL_CHARSET: return "hang";
5640 case RUSSIAN_CHARSET: return "cyrl";
5641 case SHIFTJIS_CHARSET: return "kana";
5642 case TURKISH_CHARSET: return "latn"; /* ?? */
5643 case VIETNAMESE_CHARSET: return "latn";
5644 case JOHAB_CHARSET: return "latn"; /* ?? */
5645 case ARABIC_CHARSET: return "arab";
5646 case HEBREW_CHARSET: return "hebr";
5647 case THAI_CHARSET: return "thai";
5648 default: return "latn";
5652 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5654 const GSUB_Header *header;
5655 const GSUB_Script *script;
5656 const GSUB_LangSys *language;
5657 const GSUB_Feature *feature;
5659 if (!font->GSUB_Table)
5662 header = font->GSUB_Table;
5664 script = GSUB_get_script_table(header, get_opentype_script(font));
5667 TRACE("Script not found\n");
5670 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5673 TRACE("Language not found\n");
5676 feature = GSUB_get_feature(header, language, "vrt2");
5678 feature = GSUB_get_feature(header, language, "vert");
5681 TRACE("vrt2/vert feature not found\n");
5684 return GSUB_apply_feature(header, feature, glyph);
5687 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5691 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5692 WCHAR wc = (WCHAR)glyph;
5694 BOOL *default_used_pointer;
5697 default_used_pointer = NULL;
5698 default_used = FALSE;
5699 if (codepage_sets_default_used(font->codepage))
5700 default_used_pointer = &default_used;
5701 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5703 if (font->codepage == CP_SYMBOL && wc < 0x100)
5704 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5709 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5710 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5714 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5716 if (glyph < 0x100) glyph += 0xf000;
5717 /* there is a number of old pre-Unicode "broken" TTFs, which
5718 do have symbols at U+00XX instead of U+f0XX */
5719 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5720 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5722 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5727 /*************************************************************
5728 * freetype_GetGlyphIndices
5730 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5732 struct freetype_physdev *physdev = get_freetype_dev( dev );
5735 BOOL got_default = FALSE;
5739 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5740 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5743 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5745 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5750 EnterCriticalSection( &freetype_cs );
5752 for(i = 0; i < count; i++)
5754 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5759 if (FT_IS_SFNT(physdev->font->ft_face))
5761 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5762 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5767 get_text_metrics(physdev->font, &textm);
5768 default_char = textm.tmDefaultChar;
5772 pgi[i] = default_char;
5775 LeaveCriticalSection( &freetype_cs );
5779 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5781 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5782 return !memcmp(matrix, &identity, sizeof(FMAT2));
5785 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5787 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5788 return !memcmp(matrix, &identity, sizeof(MAT2));
5791 static inline BYTE get_max_level( UINT format )
5795 case GGO_GRAY2_BITMAP: return 4;
5796 case GGO_GRAY4_BITMAP: return 16;
5797 case GGO_GRAY8_BITMAP: return 64;
5802 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5804 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5805 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5808 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5809 FT_Face ft_face = incoming_font->ft_face;
5810 GdiFont *font = incoming_font;
5811 FT_UInt glyph_index;
5812 DWORD width, height, pitch, needed = 0;
5813 FT_Bitmap ft_bitmap;
5815 INT left, right, top = 0, bottom = 0, adv;
5817 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5818 double widthRatio = 1.0;
5819 FT_Matrix transMat = identityMat;
5820 FT_Matrix transMatUnrotated;
5821 BOOL needsTransform = FALSE;
5822 BOOL tategaki = (font->GSUB_Table != NULL);
5823 UINT original_index;
5825 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5826 buflen, buf, lpmat);
5828 TRACE("font transform %f %f %f %f\n",
5829 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5830 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5832 if(format & GGO_GLYPH_INDEX) {
5833 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5834 original_index = glyph;
5835 format &= ~GGO_GLYPH_INDEX;
5837 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5838 ft_face = font->ft_face;
5839 original_index = glyph_index;
5842 if(format & GGO_UNHINTED) {
5843 load_flags |= FT_LOAD_NO_HINTING;
5844 format &= ~GGO_UNHINTED;
5847 /* tategaki never appears to happen to lower glyph index */
5848 if (glyph_index < TATEGAKI_LOWER_BOUND )
5851 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5852 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5853 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5854 font->gmsize * sizeof(GM*));
5856 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5857 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5859 *lpgm = FONT_GM(font,original_index)->gm;
5860 *abc = FONT_GM(font,original_index)->abc;
5861 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5862 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5863 lpgm->gmCellIncX, lpgm->gmCellIncY);
5864 return 1; /* FIXME */
5868 if (!font->gm[original_index / GM_BLOCK_SIZE])
5869 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5871 /* Scaling factor */
5876 get_text_metrics(font, &tm);
5878 widthRatio = (double)font->aveWidth;
5879 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5882 widthRatio = font->scale_y;
5884 /* Scaling transform */
5885 if (widthRatio != 1.0 || font->scale_y != 1.0)
5888 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5891 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5893 pFT_Matrix_Multiply(&scaleMat, &transMat);
5894 needsTransform = TRUE;
5897 /* Slant transform */
5898 if (font->fake_italic) {
5901 slantMat.xx = (1 << 16);
5902 slantMat.xy = ((1 << 16) >> 2);
5904 slantMat.yy = (1 << 16);
5905 pFT_Matrix_Multiply(&slantMat, &transMat);
5906 needsTransform = TRUE;
5909 /* Rotation transform */
5910 transMatUnrotated = transMat;
5911 if(font->orientation && !tategaki) {
5912 FT_Matrix rotationMat;
5914 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5915 pFT_Vector_Unit(&vecAngle, angle);
5916 rotationMat.xx = vecAngle.x;
5917 rotationMat.xy = -vecAngle.y;
5918 rotationMat.yx = -rotationMat.xy;
5919 rotationMat.yy = rotationMat.xx;
5921 pFT_Matrix_Multiply(&rotationMat, &transMat);
5922 needsTransform = TRUE;
5925 /* World transform */
5926 if (!is_identity_FMAT2(&font->font_desc.matrix))
5929 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5930 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
5931 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
5932 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5933 pFT_Matrix_Multiply(&worldMat, &transMat);
5934 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5935 needsTransform = TRUE;
5938 /* Extra transformation specified by caller */
5939 if (!is_identity_MAT2(lpmat))
5942 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5943 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
5944 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
5945 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5946 pFT_Matrix_Multiply(&extraMat, &transMat);
5947 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5948 needsTransform = TRUE;
5951 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
5953 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5956 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5960 if(!needsTransform) {
5961 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5962 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5963 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5965 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5966 bottom = (ft_face->glyph->metrics.horiBearingY -
5967 ft_face->glyph->metrics.height) & -64;
5968 lpgm->gmCellIncX = adv;
5969 lpgm->gmCellIncY = 0;
5976 for(xc = 0; xc < 2; xc++) {
5977 for(yc = 0; yc < 2; yc++) {
5978 vec.x = (ft_face->glyph->metrics.horiBearingX +
5979 xc * ft_face->glyph->metrics.width);
5980 vec.y = ft_face->glyph->metrics.horiBearingY -
5981 yc * ft_face->glyph->metrics.height;
5982 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5983 pFT_Vector_Transform(&vec, &transMat);
5984 if(xc == 0 && yc == 0) {
5985 left = right = vec.x;
5986 top = bottom = vec.y;
5988 if(vec.x < left) left = vec.x;
5989 else if(vec.x > right) right = vec.x;
5990 if(vec.y < bottom) bottom = vec.y;
5991 else if(vec.y > top) top = vec.y;
5996 right = (right + 63) & -64;
5997 bottom = bottom & -64;
5998 top = (top + 63) & -64;
6000 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6001 vec.x = ft_face->glyph->metrics.horiAdvance;
6003 pFT_Vector_Transform(&vec, &transMat);
6004 lpgm->gmCellIncX = (vec.x+63) >> 6;
6005 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6007 vec.x = ft_face->glyph->metrics.horiAdvance;
6009 pFT_Vector_Transform(&vec, &transMatUnrotated);
6010 adv = (vec.x+63) >> 6;
6013 lpgm->gmBlackBoxX = (right - left) >> 6;
6014 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6015 lpgm->gmptGlyphOrigin.x = left >> 6;
6016 lpgm->gmptGlyphOrigin.y = top >> 6;
6017 abc->abcA = left >> 6;
6018 abc->abcB = (right - left) >> 6;
6019 abc->abcC = adv - abc->abcA - abc->abcB;
6021 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6022 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6023 lpgm->gmCellIncX, lpgm->gmCellIncY);
6025 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6026 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6028 FONT_GM(font,original_index)->gm = *lpgm;
6029 FONT_GM(font,original_index)->abc = *abc;
6030 FONT_GM(font,original_index)->init = TRUE;
6033 if(format == GGO_METRICS)
6035 return 1; /* FIXME */
6038 if(ft_face->glyph->format != ft_glyph_format_outline &&
6039 (format == GGO_NATIVE || format == GGO_BEZIER))
6041 TRACE("loaded a bitmap\n");
6047 width = lpgm->gmBlackBoxX;
6048 height = lpgm->gmBlackBoxY;
6049 pitch = ((width + 31) >> 5) << 2;
6050 needed = pitch * height;
6052 if(!buf || !buflen) break;
6054 switch(ft_face->glyph->format) {
6055 case ft_glyph_format_bitmap:
6057 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6058 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
6059 INT h = ft_face->glyph->bitmap.rows;
6061 memcpy(dst, src, w);
6062 src += ft_face->glyph->bitmap.pitch;
6068 case ft_glyph_format_outline:
6069 ft_bitmap.width = width;
6070 ft_bitmap.rows = height;
6071 ft_bitmap.pitch = pitch;
6072 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6073 ft_bitmap.buffer = buf;
6076 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6078 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6080 /* Note: FreeType will only set 'black' bits for us. */
6081 memset(buf, 0, needed);
6082 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6086 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6091 case GGO_GRAY2_BITMAP:
6092 case GGO_GRAY4_BITMAP:
6093 case GGO_GRAY8_BITMAP:
6094 case WINE_GGO_GRAY16_BITMAP:
6096 unsigned int max_level, row, col;
6099 width = lpgm->gmBlackBoxX;
6100 height = lpgm->gmBlackBoxY;
6101 pitch = (width + 3) / 4 * 4;
6102 needed = pitch * height;
6104 if(!buf || !buflen) break;
6106 max_level = get_max_level( format );
6108 switch(ft_face->glyph->format) {
6109 case ft_glyph_format_bitmap:
6111 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6112 INT h = ft_face->glyph->bitmap.rows;
6114 memset( buf, 0, needed );
6116 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6117 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6118 src += ft_face->glyph->bitmap.pitch;
6123 case ft_glyph_format_outline:
6125 ft_bitmap.width = width;
6126 ft_bitmap.rows = height;
6127 ft_bitmap.pitch = pitch;
6128 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6129 ft_bitmap.buffer = buf;
6132 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6134 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6136 memset(ft_bitmap.buffer, 0, buflen);
6138 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6140 if (max_level != 255)
6142 for (row = 0, start = buf; row < height; row++)
6144 for (col = 0, ptr = start; col < width; col++, ptr++)
6145 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6153 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6159 case WINE_GGO_HRGB_BITMAP:
6160 case WINE_GGO_HBGR_BITMAP:
6161 case WINE_GGO_VRGB_BITMAP:
6162 case WINE_GGO_VBGR_BITMAP:
6163 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6165 switch (ft_face->glyph->format)
6167 case FT_GLYPH_FORMAT_BITMAP:
6172 width = lpgm->gmBlackBoxX;
6173 height = lpgm->gmBlackBoxY;
6175 needed = pitch * height;
6177 if (!buf || !buflen) break;
6179 memset(buf, 0, buflen);
6181 src = ft_face->glyph->bitmap.buffer;
6182 src_pitch = ft_face->glyph->bitmap.pitch;
6184 height = min( height, ft_face->glyph->bitmap.rows );
6187 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6189 if ( src[x / 8] & masks[x % 8] )
6190 ((unsigned int *)dst)[x] = ~0u;
6199 case FT_GLYPH_FORMAT_OUTLINE:
6203 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6204 INT x_shift, y_shift;
6206 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6207 FT_Render_Mode render_mode =
6208 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6209 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6211 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6213 if ( render_mode == FT_RENDER_MODE_LCD)
6215 lpgm->gmBlackBoxX += 2;
6216 lpgm->gmptGlyphOrigin.x -= 1;
6220 lpgm->gmBlackBoxY += 2;
6221 lpgm->gmptGlyphOrigin.y += 1;
6225 width = lpgm->gmBlackBoxX;
6226 height = lpgm->gmBlackBoxY;
6228 needed = pitch * height;
6230 if (!buf || !buflen) break;
6232 memset(buf, 0, buflen);
6234 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6236 if ( needsTransform )
6237 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6239 if ( pFT_Library_SetLcdFilter )
6240 pFT_Library_SetLcdFilter( library, lcdfilter );
6241 pFT_Render_Glyph (ft_face->glyph, render_mode);
6243 src = ft_face->glyph->bitmap.buffer;
6244 src_pitch = ft_face->glyph->bitmap.pitch;
6245 src_width = ft_face->glyph->bitmap.width;
6246 src_height = ft_face->glyph->bitmap.rows;
6248 if ( render_mode == FT_RENDER_MODE_LCD)
6256 rgb_interval = src_pitch;
6261 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6262 if ( x_shift < 0 ) x_shift = 0;
6263 if ( x_shift + (src_width / hmul) > width )
6264 x_shift = width - (src_width / hmul);
6266 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6267 if ( y_shift < 0 ) y_shift = 0;
6268 if ( y_shift + (src_height / vmul) > height )
6269 y_shift = height - (src_height / vmul);
6271 dst += x_shift + y_shift * ( pitch / 4 );
6272 while ( src_height )
6274 for ( x = 0; x < src_width / hmul; x++ )
6278 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6279 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6280 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6281 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6285 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6286 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6287 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6288 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6291 src += src_pitch * vmul;
6300 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6312 int contour, point = 0, first_pt;
6313 FT_Outline *outline = &ft_face->glyph->outline;
6314 TTPOLYGONHEADER *pph;
6316 DWORD pph_start, cpfx, type;
6318 if(buflen == 0) buf = NULL;
6320 if (needsTransform && buf) {
6321 pFT_Outline_Transform(outline, &transMat);
6324 for(contour = 0; contour < outline->n_contours; contour++) {
6325 /* Ignore contours containing one point */
6326 if(point == outline->contours[contour]) {
6332 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6335 pph->dwType = TT_POLYGON_TYPE;
6336 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6338 needed += sizeof(*pph);
6340 while(point <= outline->contours[contour]) {
6341 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6342 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6343 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6347 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6350 } while(point <= outline->contours[contour] &&
6351 (outline->tags[point] & FT_Curve_Tag_On) ==
6352 (outline->tags[point-1] & FT_Curve_Tag_On));
6353 /* At the end of a contour Windows adds the start point, but
6355 if(point > outline->contours[contour] &&
6356 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6358 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6360 } else if(point <= outline->contours[contour] &&
6361 outline->tags[point] & FT_Curve_Tag_On) {
6362 /* add closing pt for bezier */
6364 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6372 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6375 pph->cb = needed - pph_start;
6381 /* Convert the quadratic Beziers to cubic Beziers.
6382 The parametric eqn for a cubic Bezier is, from PLRM:
6383 r(t) = at^3 + bt^2 + ct + r0
6384 with the control points:
6389 A quadratic Bezier has the form:
6390 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6392 So equating powers of t leads to:
6393 r1 = 2/3 p1 + 1/3 p0
6394 r2 = 2/3 p1 + 1/3 p2
6395 and of course r0 = p0, r3 = p2
6398 int contour, point = 0, first_pt;
6399 FT_Outline *outline = &ft_face->glyph->outline;
6400 TTPOLYGONHEADER *pph;
6402 DWORD pph_start, cpfx, type;
6403 FT_Vector cubic_control[4];
6404 if(buflen == 0) buf = NULL;
6406 if (needsTransform && buf) {
6407 pFT_Outline_Transform(outline, &transMat);
6410 for(contour = 0; contour < outline->n_contours; contour++) {
6412 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6415 pph->dwType = TT_POLYGON_TYPE;
6416 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6418 needed += sizeof(*pph);
6420 while(point <= outline->contours[contour]) {
6421 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6422 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6423 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6426 if(type == TT_PRIM_LINE) {
6428 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6432 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6435 /* FIXME: Possible optimization in endpoint calculation
6436 if there are two consecutive curves */
6437 cubic_control[0] = outline->points[point-1];
6438 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6439 cubic_control[0].x += outline->points[point].x + 1;
6440 cubic_control[0].y += outline->points[point].y + 1;
6441 cubic_control[0].x >>= 1;
6442 cubic_control[0].y >>= 1;
6444 if(point+1 > outline->contours[contour])
6445 cubic_control[3] = outline->points[first_pt];
6447 cubic_control[3] = outline->points[point+1];
6448 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6449 cubic_control[3].x += outline->points[point].x + 1;
6450 cubic_control[3].y += outline->points[point].y + 1;
6451 cubic_control[3].x >>= 1;
6452 cubic_control[3].y >>= 1;
6455 /* r1 = 1/3 p0 + 2/3 p1
6456 r2 = 1/3 p2 + 2/3 p1 */
6457 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6458 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6459 cubic_control[2] = cubic_control[1];
6460 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6461 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6462 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6463 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6465 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6466 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6467 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6472 } while(point <= outline->contours[contour] &&
6473 (outline->tags[point] & FT_Curve_Tag_On) ==
6474 (outline->tags[point-1] & FT_Curve_Tag_On));
6475 /* At the end of a contour Windows adds the start point,
6476 but only for Beziers and we've already done that.
6478 if(point <= outline->contours[contour] &&
6479 outline->tags[point] & FT_Curve_Tag_On) {
6480 /* This is the closing pt of a bezier, but we've already
6481 added it, so just inc point and carry on */
6488 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6491 pph->cb = needed - pph_start;
6497 FIXME("Unsupported format %d\n", format);
6503 static BOOL get_bitmap_text_metrics(GdiFont *font)
6505 FT_Face ft_face = font->ft_face;
6506 FT_WinFNT_HeaderRec winfnt_header;
6507 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6508 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6509 font->potm->otmSize = size;
6511 #define TM font->potm->otmTextMetrics
6512 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6514 TM.tmHeight = winfnt_header.pixel_height;
6515 TM.tmAscent = winfnt_header.ascent;
6516 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6517 TM.tmInternalLeading = winfnt_header.internal_leading;
6518 TM.tmExternalLeading = winfnt_header.external_leading;
6519 TM.tmAveCharWidth = winfnt_header.avg_width;
6520 TM.tmMaxCharWidth = winfnt_header.max_width;
6521 TM.tmWeight = winfnt_header.weight;
6523 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6524 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6525 TM.tmFirstChar = winfnt_header.first_char;
6526 TM.tmLastChar = winfnt_header.last_char;
6527 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6528 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6529 TM.tmItalic = winfnt_header.italic;
6530 TM.tmUnderlined = font->underline;
6531 TM.tmStruckOut = font->strikeout;
6532 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6533 TM.tmCharSet = winfnt_header.charset;
6537 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6538 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6539 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6540 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6541 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6542 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6543 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6544 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6546 TM.tmDigitizedAspectX = 96; /* FIXME */
6547 TM.tmDigitizedAspectY = 96; /* FIXME */
6549 TM.tmLastChar = 255;
6550 TM.tmDefaultChar = 32;
6551 TM.tmBreakChar = 32;
6552 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6553 TM.tmUnderlined = font->underline;
6554 TM.tmStruckOut = font->strikeout;
6555 /* NB inverted meaning of TMPF_FIXED_PITCH */
6556 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6557 TM.tmCharSet = font->charset;
6565 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6567 double scale_x, scale_y;
6571 scale_x = (double)font->aveWidth;
6572 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6575 scale_x = font->scale_y;
6577 scale_x *= fabs(font->font_desc.matrix.eM11);
6578 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6580 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6581 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6583 SCALE_Y(ptm->tmHeight);
6584 SCALE_Y(ptm->tmAscent);
6585 SCALE_Y(ptm->tmDescent);
6586 SCALE_Y(ptm->tmInternalLeading);
6587 SCALE_Y(ptm->tmExternalLeading);
6588 SCALE_Y(ptm->tmOverhang);
6590 SCALE_X(ptm->tmAveCharWidth);
6591 SCALE_X(ptm->tmMaxCharWidth);
6597 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6599 double scale_x, scale_y;
6603 scale_x = (double)font->aveWidth;
6604 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6607 scale_x = font->scale_y;
6609 scale_x *= fabs(font->font_desc.matrix.eM11);
6610 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6612 scale_font_metrics(font, &potm->otmTextMetrics);
6614 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6615 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6617 SCALE_Y(potm->otmAscent);
6618 SCALE_Y(potm->otmDescent);
6619 SCALE_Y(potm->otmLineGap);
6620 SCALE_Y(potm->otmsCapEmHeight);
6621 SCALE_Y(potm->otmsXHeight);
6622 SCALE_Y(potm->otmrcFontBox.top);
6623 SCALE_Y(potm->otmrcFontBox.bottom);
6624 SCALE_X(potm->otmrcFontBox.left);
6625 SCALE_X(potm->otmrcFontBox.right);
6626 SCALE_Y(potm->otmMacAscent);
6627 SCALE_Y(potm->otmMacDescent);
6628 SCALE_Y(potm->otmMacLineGap);
6629 SCALE_X(potm->otmptSubscriptSize.x);
6630 SCALE_Y(potm->otmptSubscriptSize.y);
6631 SCALE_X(potm->otmptSubscriptOffset.x);
6632 SCALE_Y(potm->otmptSubscriptOffset.y);
6633 SCALE_X(potm->otmptSuperscriptSize.x);
6634 SCALE_Y(potm->otmptSuperscriptSize.y);
6635 SCALE_X(potm->otmptSuperscriptOffset.x);
6636 SCALE_Y(potm->otmptSuperscriptOffset.y);
6637 SCALE_Y(potm->otmsStrikeoutSize);
6638 SCALE_Y(potm->otmsStrikeoutPosition);
6639 SCALE_Y(potm->otmsUnderscoreSize);
6640 SCALE_Y(potm->otmsUnderscorePosition);
6646 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6650 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6652 /* Make sure that the font has sane width/height ratio */
6655 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6657 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6662 *ptm = font->potm->otmTextMetrics;
6663 scale_font_metrics(font, ptm);
6667 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6671 for(i = 0; i < ft_face->num_charmaps; i++)
6673 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6679 static BOOL get_outline_text_metrics(GdiFont *font)
6682 FT_Face ft_face = font->ft_face;
6683 UINT needed, lenfam, lensty, lenface, lenfull;
6685 TT_HoriHeader *pHori;
6686 TT_Postscript *pPost;
6687 FT_Fixed x_scale, y_scale;
6688 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6690 INT ascent, descent;
6692 TRACE("font=%p\n", font);
6694 if(!FT_IS_SCALABLE(ft_face))
6697 needed = sizeof(*font->potm);
6699 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6700 family_nameW = strdupW(font->name);
6702 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6704 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6707 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6708 style_nameW = towstr( CP_ACP, ft_face->style_name );
6710 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6712 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6714 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6717 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6718 face_nameW = strdupW(font->name);
6720 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6721 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6723 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6725 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6728 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6729 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6730 full_nameW = strdupW(fake_nameW);
6732 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6734 /* These names should be read from the TT name table */
6736 /* length of otmpFamilyName */
6739 /* length of otmpFaceName */
6742 /* length of otmpStyleName */
6745 /* length of otmpFullName */
6749 x_scale = ft_face->size->metrics.x_scale;
6750 y_scale = ft_face->size->metrics.y_scale;
6752 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6754 FIXME("Can't find OS/2 table - not TT font?\n");
6758 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6760 FIXME("Can't find HHEA table - not TT font?\n");
6764 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6766 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",
6767 pOS2->usWinAscent, pOS2->usWinDescent,
6768 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6769 pOS2->xAvgCharWidth,
6770 ft_face->ascender, ft_face->descender, ft_face->height,
6771 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6772 ft_face->bbox.yMax, ft_face->bbox.yMin);
6774 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6775 font->potm->otmSize = needed;
6777 #define TM font->potm->otmTextMetrics
6779 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6780 ascent = pHori->Ascender;
6781 descent = -pHori->Descender;
6783 ascent = pOS2->usWinAscent;
6784 descent = pOS2->usWinDescent;
6787 font->ntmCellHeight = ascent + descent;
6788 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6791 TM.tmAscent = font->yMax;
6792 TM.tmDescent = -font->yMin;
6793 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6795 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6796 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6797 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6798 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6801 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6804 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6806 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6807 ((ascent + descent) -
6808 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6810 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6811 if (TM.tmAveCharWidth == 0) {
6812 TM.tmAveCharWidth = 1;
6814 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6815 TM.tmWeight = FW_REGULAR;
6816 if (font->fake_bold)
6817 TM.tmWeight = FW_BOLD;
6820 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6822 if (pOS2->usWeightClass > FW_MEDIUM)
6823 TM.tmWeight = pOS2->usWeightClass;
6825 else if (pOS2->usWeightClass <= FW_MEDIUM)
6826 TM.tmWeight = pOS2->usWeightClass;
6829 TM.tmDigitizedAspectX = 96; /* FIXME */
6830 TM.tmDigitizedAspectY = 96; /* FIXME */
6831 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6832 * symbol range to 0 - f0ff
6835 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6840 case 1257: /* Baltic */
6841 TM.tmLastChar = 0xf8fd;
6844 TM.tmLastChar = 0xf0ff;
6846 TM.tmBreakChar = 0x20;
6847 TM.tmDefaultChar = 0x1f;
6851 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6852 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6854 if(pOS2->usFirstCharIndex <= 1)
6855 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6856 else if (pOS2->usFirstCharIndex > 0xff)
6857 TM.tmBreakChar = 0x20;
6859 TM.tmBreakChar = pOS2->usFirstCharIndex;
6860 TM.tmDefaultChar = TM.tmBreakChar - 1;
6862 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6863 TM.tmUnderlined = font->underline;
6864 TM.tmStruckOut = font->strikeout;
6866 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6867 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6868 (pOS2->version == 0xFFFFU ||
6869 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6870 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6872 TM.tmPitchAndFamily = 0;
6874 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6876 case PAN_FAMILY_SCRIPT:
6877 TM.tmPitchAndFamily |= FF_SCRIPT;
6880 case PAN_FAMILY_DECORATIVE:
6881 TM.tmPitchAndFamily |= FF_DECORATIVE;
6886 case PAN_FAMILY_TEXT_DISPLAY:
6887 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6888 /* which is clearly not what the panose spec says. */
6890 if(TM.tmPitchAndFamily == 0 || /* fixed */
6891 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6892 TM.tmPitchAndFamily = FF_MODERN;
6895 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6900 TM.tmPitchAndFamily |= FF_DONTCARE;
6903 case PAN_SERIF_COVE:
6904 case PAN_SERIF_OBTUSE_COVE:
6905 case PAN_SERIF_SQUARE_COVE:
6906 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6907 case PAN_SERIF_SQUARE:
6908 case PAN_SERIF_THIN:
6909 case PAN_SERIF_BONE:
6910 case PAN_SERIF_EXAGGERATED:
6911 case PAN_SERIF_TRIANGLE:
6912 TM.tmPitchAndFamily |= FF_ROMAN;
6915 case PAN_SERIF_NORMAL_SANS:
6916 case PAN_SERIF_OBTUSE_SANS:
6917 case PAN_SERIF_PERP_SANS:
6918 case PAN_SERIF_FLARED:
6919 case PAN_SERIF_ROUNDED:
6920 TM.tmPitchAndFamily |= FF_SWISS;
6927 if(FT_IS_SCALABLE(ft_face))
6928 TM.tmPitchAndFamily |= TMPF_VECTOR;
6930 if(FT_IS_SFNT(ft_face))
6932 if (font->ntmFlags & NTM_PS_OPENTYPE)
6933 TM.tmPitchAndFamily |= TMPF_DEVICE;
6935 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6938 TM.tmCharSet = font->charset;
6940 font->potm->otmFiller = 0;
6941 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6942 font->potm->otmfsSelection = pOS2->fsSelection;
6943 font->potm->otmfsType = pOS2->fsType;
6944 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6945 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6946 font->potm->otmItalicAngle = 0; /* POST table */
6947 font->potm->otmEMSquare = ft_face->units_per_EM;
6948 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6949 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6950 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6951 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6952 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6953 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6954 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6955 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6956 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6957 font->potm->otmMacAscent = TM.tmAscent;
6958 font->potm->otmMacDescent = -TM.tmDescent;
6959 font->potm->otmMacLineGap = font->potm->otmLineGap;
6960 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6961 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6962 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6963 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6964 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6965 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6966 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6967 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6968 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6969 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6970 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6972 font->potm->otmsUnderscoreSize = 0;
6973 font->potm->otmsUnderscorePosition = 0;
6975 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6976 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6980 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6981 cp = (char*)font->potm + sizeof(*font->potm);
6982 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6983 strcpyW((WCHAR*)cp, family_nameW);
6985 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6986 strcpyW((WCHAR*)cp, style_nameW);
6988 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6989 strcpyW((WCHAR*)cp, face_nameW);
6991 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6992 strcpyW((WCHAR*)cp, full_nameW);
6996 HeapFree(GetProcessHeap(), 0, style_nameW);
6997 HeapFree(GetProcessHeap(), 0, family_nameW);
6998 HeapFree(GetProcessHeap(), 0, face_nameW);
6999 HeapFree(GetProcessHeap(), 0, full_nameW);
7003 /*************************************************************
7004 * freetype_GetGlyphOutline
7006 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7007 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7009 struct freetype_physdev *physdev = get_freetype_dev( dev );
7015 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7016 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7020 EnterCriticalSection( &freetype_cs );
7021 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7022 LeaveCriticalSection( &freetype_cs );
7026 /*************************************************************
7027 * freetype_GetTextMetrics
7029 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7031 struct freetype_physdev *physdev = get_freetype_dev( dev );
7036 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7037 return dev->funcs->pGetTextMetrics( dev, metrics );
7041 EnterCriticalSection( &freetype_cs );
7042 ret = get_text_metrics( physdev->font, metrics );
7043 LeaveCriticalSection( &freetype_cs );
7047 /*************************************************************
7048 * freetype_GetOutlineTextMetrics
7050 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7052 struct freetype_physdev *physdev = get_freetype_dev( dev );
7057 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7058 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7061 TRACE("font=%p\n", physdev->font);
7063 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7066 EnterCriticalSection( &freetype_cs );
7068 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7070 if(cbSize >= physdev->font->potm->otmSize)
7072 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7073 scale_outline_font_metrics(physdev->font, potm);
7075 ret = physdev->font->potm->otmSize;
7077 LeaveCriticalSection( &freetype_cs );
7081 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7083 child->font = alloc_font();
7084 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7085 if(!child->font->ft_face)
7087 free_font(child->font);
7092 child->font->font_desc = font->font_desc;
7093 child->font->ntmFlags = child->face->ntmFlags;
7094 child->font->orientation = font->orientation;
7095 child->font->scale_y = font->scale_y;
7096 child->font->name = strdupW(child->face->family->FamilyName);
7097 child->font->base_font = font;
7098 TRACE("created child font %p for base %p\n", child->font, font);
7102 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7105 CHILD_FONT *child_font;
7108 font = font->base_font;
7110 *linked_font = font;
7112 if((*glyph = get_glyph_index(font, c)))
7114 *glyph = get_GSUB_vert_glyph(font, *glyph);
7118 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7120 if(!child_font->font)
7121 if(!load_child_font(font, child_font))
7124 if(!child_font->font->ft_face)
7126 g = get_glyph_index(child_font->font, c);
7127 g = get_GSUB_vert_glyph(child_font->font, g);
7131 *linked_font = child_font->font;
7138 /*************************************************************
7139 * freetype_GetCharWidth
7141 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7143 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7147 struct freetype_physdev *physdev = get_freetype_dev( dev );
7151 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7152 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7155 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7158 EnterCriticalSection( &freetype_cs );
7159 for(c = firstChar; c <= lastChar; c++) {
7160 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7161 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7163 LeaveCriticalSection( &freetype_cs );
7167 /*************************************************************
7168 * freetype_GetCharABCWidths
7170 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7172 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7175 struct freetype_physdev *physdev = get_freetype_dev( dev );
7179 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7180 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7183 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7186 EnterCriticalSection( &freetype_cs );
7188 for(c = firstChar; c <= lastChar; c++, buffer++)
7189 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7191 LeaveCriticalSection( &freetype_cs );
7195 /*************************************************************
7196 * freetype_GetCharABCWidthsI
7198 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7200 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7203 struct freetype_physdev *physdev = get_freetype_dev( dev );
7207 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7208 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7211 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7215 EnterCriticalSection( &freetype_cs );
7217 for(c = 0; c < count; c++, buffer++)
7218 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7219 &gm, buffer, 0, NULL, &identity );
7221 LeaveCriticalSection( &freetype_cs );
7225 /*************************************************************
7226 * freetype_GetTextExtentExPoint
7228 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7230 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7234 struct freetype_physdev *physdev = get_freetype_dev( dev );
7238 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7239 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7242 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7245 EnterCriticalSection( &freetype_cs );
7247 for (idx = pos = 0; idx < count; idx++)
7249 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7250 pos += abc.abcA + abc.abcB + abc.abcC;
7254 LeaveCriticalSection( &freetype_cs );
7258 /*************************************************************
7259 * freetype_GetTextExtentExPointI
7261 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7263 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7267 struct freetype_physdev *physdev = get_freetype_dev( dev );
7271 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7272 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7275 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7278 EnterCriticalSection( &freetype_cs );
7280 for (idx = pos = 0; idx < count; idx++)
7282 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7283 &gm, &abc, 0, NULL, &identity );
7284 pos += abc.abcA + abc.abcB + abc.abcC;
7288 LeaveCriticalSection( &freetype_cs );
7292 /*************************************************************
7293 * freetype_GetFontData
7295 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7297 struct freetype_physdev *physdev = get_freetype_dev( dev );
7301 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7302 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7305 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7306 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7307 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7309 return get_font_data( physdev->font, table, offset, buf, cbData );
7312 /*************************************************************
7313 * freetype_GetTextFace
7315 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7318 struct freetype_physdev *physdev = get_freetype_dev( dev );
7322 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7323 return dev->funcs->pGetTextFace( dev, count, str );
7326 n = strlenW(physdev->font->name) + 1;
7329 lstrcpynW(str, physdev->font->name, count);
7335 /*************************************************************
7336 * freetype_GetTextCharsetInfo
7338 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7340 struct freetype_physdev *physdev = get_freetype_dev( dev );
7344 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7345 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7347 if (fs) *fs = physdev->font->fs;
7348 return physdev->font->charset;
7351 /* Retrieve a list of supported Unicode ranges for a given font.
7352 * Can be called with NULL gs to calculate the buffer size. Returns
7353 * the number of ranges found.
7355 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7357 DWORD num_ranges = 0;
7359 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7362 FT_ULong char_code, char_code_prev;
7365 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7367 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7368 face->num_glyphs, glyph_code, char_code);
7370 if (!glyph_code) return 0;
7374 gs->ranges[0].wcLow = (USHORT)char_code;
7375 gs->ranges[0].cGlyphs = 0;
7376 gs->cGlyphsSupported = 0;
7382 if (char_code < char_code_prev)
7384 ERR("expected increasing char code from FT_Get_Next_Char\n");
7387 if (char_code - char_code_prev > 1)
7392 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7393 gs->ranges[num_ranges - 1].cGlyphs = 1;
7394 gs->cGlyphsSupported++;
7399 gs->ranges[num_ranges - 1].cGlyphs++;
7400 gs->cGlyphsSupported++;
7402 char_code_prev = char_code;
7403 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7407 FIXME("encoding %u not supported\n", face->charmap->encoding);
7412 /*************************************************************
7413 * freetype_GetFontUnicodeRanges
7415 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7417 struct freetype_physdev *physdev = get_freetype_dev( dev );
7418 DWORD size, num_ranges;
7422 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7423 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7426 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7427 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7430 glyphset->cbThis = size;
7431 glyphset->cRanges = num_ranges;
7432 glyphset->flAccel = 0;
7437 /*************************************************************
7438 * freetype_FontIsLinked
7440 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7442 struct freetype_physdev *physdev = get_freetype_dev( dev );
7447 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7448 return dev->funcs->pFontIsLinked( dev );
7452 EnterCriticalSection( &freetype_cs );
7453 ret = !list_empty(&physdev->font->child_fonts);
7454 LeaveCriticalSection( &freetype_cs );
7458 /*************************************************************************
7459 * GetRasterizerCaps (GDI32.@)
7461 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7463 lprs->nSize = sizeof(RASTERIZER_STATUS);
7464 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7465 lprs->nLanguageID = 0;
7469 /*************************************************************
7470 * freetype_GdiRealizationInfo
7472 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7474 struct freetype_physdev *physdev = get_freetype_dev( dev );
7475 realization_info_t *info = ptr;
7479 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7480 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7483 FIXME("(%p, %p): stub!\n", physdev->font, info);
7486 if(FT_IS_SCALABLE(physdev->font->ft_face))
7489 info->cache_num = physdev->font->cache_num;
7490 info->unknown2 = -1;
7494 /*************************************************************************
7495 * Kerning support for TrueType fonts
7497 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7499 struct TT_kern_table
7505 struct TT_kern_subtable
7514 USHORT horizontal : 1;
7516 USHORT cross_stream: 1;
7517 USHORT override : 1;
7518 USHORT reserved1 : 4;
7524 struct TT_format0_kern_subtable
7528 USHORT entrySelector;
7539 static DWORD parse_format0_kern_subtable(GdiFont *font,
7540 const struct TT_format0_kern_subtable *tt_f0_ks,
7541 const USHORT *glyph_to_char,
7542 KERNINGPAIR *kern_pair, DWORD cPairs)
7545 const struct TT_kern_pair *tt_kern_pair;
7547 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7549 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7551 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7552 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7553 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7555 if (!kern_pair || !cPairs)
7558 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7560 nPairs = min(nPairs, cPairs);
7562 for (i = 0; i < nPairs; i++)
7564 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7565 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7566 /* this algorithm appears to better match what Windows does */
7567 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7568 if (kern_pair->iKernAmount < 0)
7570 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7571 kern_pair->iKernAmount -= font->ppem;
7573 else if (kern_pair->iKernAmount > 0)
7575 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7576 kern_pair->iKernAmount += font->ppem;
7578 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7580 TRACE("left %u right %u value %d\n",
7581 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7585 TRACE("copied %u entries\n", nPairs);
7589 /*************************************************************
7590 * freetype_GetKerningPairs
7592 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7596 const struct TT_kern_table *tt_kern_table;
7597 const struct TT_kern_subtable *tt_kern_subtable;
7599 USHORT *glyph_to_char;
7601 struct freetype_physdev *physdev = get_freetype_dev( dev );
7603 if (!(font = physdev->font))
7605 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7606 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7610 EnterCriticalSection( &freetype_cs );
7611 if (font->total_kern_pairs != (DWORD)-1)
7613 if (cPairs && kern_pair)
7615 cPairs = min(cPairs, font->total_kern_pairs);
7616 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7618 else cPairs = font->total_kern_pairs;
7620 LeaveCriticalSection( &freetype_cs );
7624 font->total_kern_pairs = 0;
7626 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7628 if (length == GDI_ERROR)
7630 TRACE("no kerning data in the font\n");
7631 LeaveCriticalSection( &freetype_cs );
7635 buf = HeapAlloc(GetProcessHeap(), 0, length);
7638 WARN("Out of memory\n");
7639 LeaveCriticalSection( &freetype_cs );
7643 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7645 /* build a glyph index to char code map */
7646 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7649 WARN("Out of memory allocating a glyph index to char code map\n");
7650 HeapFree(GetProcessHeap(), 0, buf);
7651 LeaveCriticalSection( &freetype_cs );
7655 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7661 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7663 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7664 font->ft_face->num_glyphs, glyph_code, char_code);
7668 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7670 /* FIXME: This doesn't match what Windows does: it does some fancy
7671 * things with duplicate glyph index to char code mappings, while
7672 * we just avoid overriding existing entries.
7674 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7675 glyph_to_char[glyph_code] = (USHORT)char_code;
7677 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7684 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7685 for (n = 0; n <= 65535; n++)
7686 glyph_to_char[n] = (USHORT)n;
7689 tt_kern_table = buf;
7690 nTables = GET_BE_WORD(tt_kern_table->nTables);
7691 TRACE("version %u, nTables %u\n",
7692 GET_BE_WORD(tt_kern_table->version), nTables);
7694 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7696 for (i = 0; i < nTables; i++)
7698 struct TT_kern_subtable tt_kern_subtable_copy;
7700 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7701 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7702 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7704 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7705 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7706 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7708 /* According to the TrueType specification this is the only format
7709 * that will be properly interpreted by Windows and OS/2
7711 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7713 DWORD new_chunk, old_total = font->total_kern_pairs;
7715 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7716 glyph_to_char, NULL, 0);
7717 font->total_kern_pairs += new_chunk;
7719 if (!font->kern_pairs)
7720 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7721 font->total_kern_pairs * sizeof(*font->kern_pairs));
7723 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7724 font->total_kern_pairs * sizeof(*font->kern_pairs));
7726 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7727 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7730 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7732 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7735 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7736 HeapFree(GetProcessHeap(), 0, buf);
7738 if (cPairs && kern_pair)
7740 cPairs = min(cPairs, font->total_kern_pairs);
7741 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7743 else cPairs = font->total_kern_pairs;
7745 LeaveCriticalSection( &freetype_cs );
7749 static const struct gdi_dc_funcs freetype_funcs =
7751 NULL, /* pAbortDoc */
7752 NULL, /* pAbortPath */
7753 NULL, /* pAlphaBlend */
7754 NULL, /* pAngleArc */
7757 NULL, /* pBeginPath */
7758 NULL, /* pBlendImage */
7760 NULL, /* pCloseFigure */
7761 NULL, /* pCreateCompatibleDC */
7762 freetype_CreateDC, /* pCreateDC */
7763 freetype_DeleteDC, /* pDeleteDC */
7764 NULL, /* pDeleteObject */
7765 NULL, /* pDeviceCapabilities */
7766 NULL, /* pEllipse */
7768 NULL, /* pEndPage */
7769 NULL, /* pEndPath */
7770 freetype_EnumFonts, /* pEnumFonts */
7771 NULL, /* pEnumICMProfiles */
7772 NULL, /* pExcludeClipRect */
7773 NULL, /* pExtDeviceMode */
7774 NULL, /* pExtEscape */
7775 NULL, /* pExtFloodFill */
7776 NULL, /* pExtSelectClipRgn */
7777 NULL, /* pExtTextOut */
7778 NULL, /* pFillPath */
7779 NULL, /* pFillRgn */
7780 NULL, /* pFlattenPath */
7781 freetype_FontIsLinked, /* pFontIsLinked */
7782 NULL, /* pFrameRgn */
7783 NULL, /* pGdiComment */
7784 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7785 NULL, /* pGetBoundsRect */
7786 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7787 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7788 freetype_GetCharWidth, /* pGetCharWidth */
7789 NULL, /* pGetDeviceCaps */
7790 NULL, /* pGetDeviceGammaRamp */
7791 freetype_GetFontData, /* pGetFontData */
7792 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7793 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7794 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7795 NULL, /* pGetICMProfile */
7796 NULL, /* pGetImage */
7797 freetype_GetKerningPairs, /* pGetKerningPairs */
7798 NULL, /* pGetNearestColor */
7799 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7800 NULL, /* pGetPixel */
7801 NULL, /* pGetSystemPaletteEntries */
7802 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7803 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7804 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7805 freetype_GetTextFace, /* pGetTextFace */
7806 freetype_GetTextMetrics, /* pGetTextMetrics */
7807 NULL, /* pGradientFill */
7808 NULL, /* pIntersectClipRect */
7809 NULL, /* pInvertRgn */
7811 NULL, /* pModifyWorldTransform */
7813 NULL, /* pOffsetClipRgn */
7814 NULL, /* pOffsetViewportOrg */
7815 NULL, /* pOffsetWindowOrg */
7816 NULL, /* pPaintRgn */
7819 NULL, /* pPolyBezier */
7820 NULL, /* pPolyBezierTo */
7821 NULL, /* pPolyDraw */
7822 NULL, /* pPolyPolygon */
7823 NULL, /* pPolyPolyline */
7824 NULL, /* pPolygon */
7825 NULL, /* pPolyline */
7826 NULL, /* pPolylineTo */
7827 NULL, /* pPutImage */
7828 NULL, /* pRealizeDefaultPalette */
7829 NULL, /* pRealizePalette */
7830 NULL, /* pRectangle */
7831 NULL, /* pResetDC */
7832 NULL, /* pRestoreDC */
7833 NULL, /* pRoundRect */
7835 NULL, /* pScaleViewportExt */
7836 NULL, /* pScaleWindowExt */
7837 NULL, /* pSelectBitmap */
7838 NULL, /* pSelectBrush */
7839 NULL, /* pSelectClipPath */
7840 freetype_SelectFont, /* pSelectFont */
7841 NULL, /* pSelectPalette */
7842 NULL, /* pSelectPen */
7843 NULL, /* pSetArcDirection */
7844 NULL, /* pSetBkColor */
7845 NULL, /* pSetBkMode */
7846 NULL, /* pSetDCBrushColor */
7847 NULL, /* pSetDCPenColor */
7848 NULL, /* pSetDIBColorTable */
7849 NULL, /* pSetDIBitsToDevice */
7850 NULL, /* pSetDeviceClipping */
7851 NULL, /* pSetDeviceGammaRamp */
7852 NULL, /* pSetLayout */
7853 NULL, /* pSetMapMode */
7854 NULL, /* pSetMapperFlags */
7855 NULL, /* pSetPixel */
7856 NULL, /* pSetPolyFillMode */
7857 NULL, /* pSetROP2 */
7858 NULL, /* pSetRelAbs */
7859 NULL, /* pSetStretchBltMode */
7860 NULL, /* pSetTextAlign */
7861 NULL, /* pSetTextCharacterExtra */
7862 NULL, /* pSetTextColor */
7863 NULL, /* pSetTextJustification */
7864 NULL, /* pSetViewportExt */
7865 NULL, /* pSetViewportOrg */
7866 NULL, /* pSetWindowExt */
7867 NULL, /* pSetWindowOrg */
7868 NULL, /* pSetWorldTransform */
7869 NULL, /* pStartDoc */
7870 NULL, /* pStartPage */
7871 NULL, /* pStretchBlt */
7872 NULL, /* pStretchDIBits */
7873 NULL, /* pStrokeAndFillPath */
7874 NULL, /* pStrokePath */
7875 NULL, /* pUnrealizePalette */
7876 NULL, /* pWidenPath */
7877 NULL, /* wine_get_wgl_driver */
7878 GDI_PRIORITY_FONT_DRV /* priority */
7881 #else /* HAVE_FREETYPE */
7883 /*************************************************************************/
7885 BOOL WineEngInit(void)
7890 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7892 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7896 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7898 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7902 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7904 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7908 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7909 LPCWSTR font_file, LPCWSTR font_path )
7915 /*************************************************************************
7916 * GetRasterizerCaps (GDI32.@)
7918 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7920 lprs->nSize = sizeof(RASTERIZER_STATUS);
7922 lprs->nLanguageID = 0;
7926 #endif /* HAVE_FREETYPE */