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 {
266 DWORD font_data_size;
270 FT_Fixed font_version;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily *family;
277 /* Cached data for Enum */
278 struct enum_data *cached_enum_data;
281 typedef struct tagFamily {
286 struct list *replacement;
291 ABC abc; /* metrics of the unrotated char */
307 typedef struct tagHFONTLIST {
312 typedef struct tagGdiFont GdiFont;
324 struct list hfontlist;
325 OUTLINETEXTMETRICW *potm;
326 DWORD total_kern_pairs;
327 KERNINGPAIR *kern_pairs;
328 struct list child_fonts;
330 /* the following members can be accessed without locking, they are never modified after creation */
332 struct font_mapping *mapping;
348 UINT ntmCellHeight, ntmAvgWidth;
357 const WCHAR *font_name;
362 struct enum_charset_element {
365 WCHAR name[LF_FACESIZE];
368 struct enum_charset_list {
370 struct enum_charset_element element[32];
373 #define GM_BLOCK_SIZE 128
374 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
376 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
377 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
378 #define UNUSED_CACHE_SIZE 10
379 static struct list system_links = LIST_INIT(system_links);
381 static struct list font_subst_list = LIST_INIT(font_subst_list);
383 static struct list font_list = LIST_INIT(font_list);
385 struct freetype_physdev
387 struct gdi_physdev dev;
391 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
393 return (struct freetype_physdev *)dev;
396 static const struct gdi_dc_funcs freetype_funcs;
398 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
399 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
400 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
402 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
403 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
404 'W','i','n','d','o','w','s','\\',
405 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
406 'F','o','n','t','s','\0'};
408 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
409 'W','i','n','d','o','w','s',' ','N','T','\\',
410 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
411 'F','o','n','t','s','\0'};
413 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
414 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
415 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
416 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
418 static const WCHAR * const SystemFontValues[] = {
425 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
426 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
428 /* Interesting and well-known (frequently-assumed!) font names */
429 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
430 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 };
431 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
432 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
433 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
434 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
435 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
436 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
438 static const WCHAR arial[] = {'A','r','i','a','l',0};
439 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
440 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};
441 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};
442 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
443 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
444 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
445 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
446 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
447 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
449 static const WCHAR *default_serif_list[] =
453 bitstream_vera_serif,
457 static const WCHAR *default_fixed_list[] =
461 bitstream_vera_sans_mono,
465 static const WCHAR *default_sans_list[] =
478 typedef struct tagFontSubst {
484 /* Registry font cache key and value names */
485 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
486 'F','o','n','t','s',0};
487 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
488 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
489 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
490 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
491 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
492 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
493 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
494 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
495 static const WCHAR face_size_value[] = {'S','i','z','e',0};
496 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
497 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
498 static const WCHAR face_aa_value[] = {'A','n','t','i','a','l','i','a','s','i','n','g',0};
499 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
500 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
501 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
502 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
515 static struct list mappings_list = LIST_INIT( mappings_list );
517 static UINT default_aa_flags;
519 static CRITICAL_SECTION freetype_cs;
520 static CRITICAL_SECTION_DEBUG critsect_debug =
523 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
524 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
526 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
528 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
530 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
531 static BOOL use_default_fallback = FALSE;
533 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
534 static BOOL get_outline_text_metrics(GdiFont *font);
535 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
537 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
538 'W','i','n','d','o','w','s',' ','N','T','\\',
539 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
540 'S','y','s','t','e','m','L','i','n','k',0};
542 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
543 'F','o','n','t','L','i','n','k','\\',
544 'S','y','s','t','e','m','L','i','n','k',0};
546 /****************************************
547 * Notes on .fon files
549 * The fonts System, FixedSys and Terminal are special. There are typically multiple
550 * versions installed for different resolutions and codepages. Windows stores which one to use
551 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
553 * FIXEDFON.FON FixedSys
555 * OEMFONT.FON Terminal
556 * LogPixels Current dpi set by the display control panel applet
557 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
558 * also has a LogPixels value that appears to mirror this)
560 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
561 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
562 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
563 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
564 * so that makes sense.
566 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
567 * to be mapped into the registry on Windows 2000 at least).
570 * ega80woa.fon=ega80850.fon
571 * ega40woa.fon=ega40850.fon
572 * cga80woa.fon=cga80850.fon
573 * cga40woa.fon=cga40850.fon
576 /* These are all structures needed for the GSUB table */
578 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
579 #define TATEGAKI_LOWER_BOUND 0x02F1
595 GSUB_ScriptRecord ScriptRecord[1];
601 } GSUB_LangSysRecord;
606 GSUB_LangSysRecord LangSysRecord[1];
610 WORD LookupOrder; /* Reserved */
611 WORD ReqFeatureIndex;
613 WORD FeatureIndex[1];
619 } GSUB_FeatureRecord;
623 GSUB_FeatureRecord FeatureRecord[1];
627 WORD FeatureParams; /* Reserved */
629 WORD LookupListIndex[1];
648 } GSUB_CoverageFormat1;
653 WORD StartCoverageIndex;
659 GSUB_RangeRecord RangeRecord[1];
660 } GSUB_CoverageFormat2;
663 WORD SubstFormat; /* = 1 */
666 } GSUB_SingleSubstFormat1;
669 WORD SubstFormat; /* = 2 */
673 }GSUB_SingleSubstFormat2;
675 #ifdef HAVE_CARBON_CARBON_H
676 static char *find_cache_dir(void)
680 static char cached_path[MAX_PATH];
681 static const char *wine = "/Wine", *fonts = "/Fonts";
683 if(*cached_path) return cached_path;
685 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
688 WARN("can't create cached data folder\n");
691 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
694 WARN("can't create cached data path\n");
698 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
700 ERR("Could not create full path\n");
704 strcat(cached_path, wine);
706 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
708 WARN("Couldn't mkdir %s\n", cached_path);
712 strcat(cached_path, fonts);
713 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
715 WARN("Couldn't mkdir %s\n", cached_path);
722 /******************************************************************
725 * Extracts individual TrueType font files from a Mac suitcase font
726 * and saves them into the user's caches directory (see
728 * Returns a NULL terminated array of filenames.
730 * We do this because they are apps that try to read ttf files
731 * themselves and they don't like Mac suitcase files.
733 static char **expand_mac_font(const char *path)
740 const char *filename;
744 unsigned int size, max_size;
747 TRACE("path %s\n", path);
749 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
752 WARN("failed to get ref\n");
756 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
759 TRACE("no data fork, so trying resource fork\n");
760 res_ref = FSOpenResFile(&ref, fsRdPerm);
763 TRACE("unable to open resource fork\n");
770 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
773 CloseResFile(res_ref);
777 out_dir = find_cache_dir();
779 filename = strrchr(path, '/');
780 if(!filename) filename = path;
783 /* output filename has the form out_dir/filename_%04x.ttf */
784 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
791 unsigned short *num_faces_ptr, num_faces, face;
794 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
796 fond = Get1IndResource(fond_res, idx);
798 TRACE("got fond resource %d\n", idx);
801 fam_rec = *(FamRec**)fond;
802 num_faces_ptr = (unsigned short *)(fam_rec + 1);
803 num_faces = GET_BE_WORD(*num_faces_ptr);
805 assoc = (AsscEntry*)(num_faces_ptr + 1);
806 TRACE("num faces %04x\n", num_faces);
807 for(face = 0; face < num_faces; face++, assoc++)
810 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
811 unsigned short size, font_id;
814 size = GET_BE_WORD(assoc->fontSize);
815 font_id = GET_BE_WORD(assoc->fontID);
818 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
822 TRACE("trying to load sfnt id %04x\n", font_id);
823 sfnt = GetResource(sfnt_res, font_id);
826 TRACE("can't get sfnt resource %04x\n", font_id);
830 output = HeapAlloc(GetProcessHeap(), 0, output_len);
835 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
837 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
838 if(fd != -1 || errno == EEXIST)
842 unsigned char *sfnt_data;
845 sfnt_data = *(unsigned char**)sfnt;
846 write(fd, sfnt_data, GetHandleSize(sfnt));
850 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
853 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
855 ret.array[ret.size++] = output;
859 WARN("unable to create %s\n", output);
860 HeapFree(GetProcessHeap(), 0, output);
863 ReleaseResource(sfnt);
866 ReleaseResource(fond);
869 CloseResFile(res_ref);
874 #endif /* HAVE_CARBON_CARBON_H */
876 static inline BOOL is_win9x(void)
878 return GetVersion() & 0x80000000;
881 This function builds an FT_Fixed from a double. It fails if the absolute
882 value of the float number is greater than 32768.
884 static inline FT_Fixed FT_FixedFromFloat(double f)
890 This function builds an FT_Fixed from a FIXED. It simply put f.value
891 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
893 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
895 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
898 static BOOL is_hinting_enabled(void)
900 static int enabled = -1;
904 /* Use the >= 2.2.0 function if available */
905 if (pFT_Get_TrueType_Engine_Type)
907 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
908 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
910 #ifdef FT_DRIVER_HAS_HINTER
913 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
914 FT_Module mod = pFT_Get_Module(library, "truetype");
915 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
918 else enabled = FALSE;
919 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
924 static BOOL is_subpixel_rendering_enabled( void )
926 #ifdef HAVE_FREETYPE_FTLCDFIL_H
927 static int enabled = -1;
930 enabled = (pFT_Library_SetLcdFilter &&
931 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
932 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
941 static const struct list *get_face_list_from_family(const Family *family)
943 if (!list_empty(&family->faces))
944 return &family->faces;
946 return family->replacement;
949 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
955 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
957 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
959 const struct list *face_list;
960 if(face_name && strcmpiW(face_name, family->FamilyName))
962 face_list = get_face_list_from_family(family);
963 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
967 file = strrchrW(face->file, '/');
972 if(!strcmpiW(file, file_name)) return face;
978 static Family *find_family_from_name(const WCHAR *name)
982 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
984 if(!strcmpiW(family->FamilyName, name))
991 static Family *find_family_from_any_name(const WCHAR *name)
995 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
997 if(!strcmpiW(family->FamilyName, name))
999 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1006 static void DumpSubstList(void)
1010 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1012 if(psub->from.charset != -1 || psub->to.charset != -1)
1013 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1014 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1016 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1017 debugstr_w(psub->to.name));
1022 static LPWSTR strdupW(LPCWSTR p)
1025 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1026 ret = HeapAlloc(GetProcessHeap(), 0, len);
1027 memcpy(ret, p, len);
1031 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1036 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1038 if(!strcmpiW(element->from.name, from_name) &&
1039 (element->from.charset == from_charset ||
1040 element->from.charset == -1))
1047 #define ADD_FONT_SUBST_FORCE 1
1049 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1051 FontSubst *from_exist, *to_exist;
1053 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1055 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1057 list_remove(&from_exist->entry);
1058 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1059 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1060 HeapFree(GetProcessHeap(), 0, from_exist);
1066 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1070 HeapFree(GetProcessHeap(), 0, subst->to.name);
1071 subst->to.name = strdupW(to_exist->to.name);
1074 list_add_tail(subst_list, &subst->entry);
1079 HeapFree(GetProcessHeap(), 0, subst->from.name);
1080 HeapFree(GetProcessHeap(), 0, subst->to.name);
1081 HeapFree(GetProcessHeap(), 0, subst);
1085 static WCHAR *towstr(UINT cp, const char *str)
1090 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1091 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1092 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1096 static char *strWtoA(UINT cp, const WCHAR *str)
1098 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1099 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1100 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1104 static void split_subst_info(NameCs *nc, LPSTR str)
1106 CHAR *p = strrchr(str, ',');
1110 nc->charset = strtol(p+1, NULL, 10);
1113 nc->name = towstr(CP_ACP, str);
1116 static void LoadSubstList(void)
1120 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1124 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1125 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1126 &hkey) == ERROR_SUCCESS) {
1128 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1129 &valuelen, &datalen, NULL, NULL);
1131 valuelen++; /* returned value doesn't include room for '\0' */
1132 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1133 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1137 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1138 &dlen) == ERROR_SUCCESS) {
1139 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1141 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1142 split_subst_info(&psub->from, value);
1143 split_subst_info(&psub->to, data);
1145 /* Win 2000 doesn't allow mapping between different charsets
1146 or mapping of DEFAULT_CHARSET */
1147 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1148 psub->to.charset == DEFAULT_CHARSET) {
1149 HeapFree(GetProcessHeap(), 0, psub->to.name);
1150 HeapFree(GetProcessHeap(), 0, psub->from.name);
1151 HeapFree(GetProcessHeap(), 0, psub);
1153 add_font_subst(&font_subst_list, psub, 0);
1155 /* reset dlen and vlen */
1159 HeapFree(GetProcessHeap(), 0, data);
1160 HeapFree(GetProcessHeap(), 0, value);
1166 /*****************************************************************
1167 * get_name_table_entry
1169 * Supply the platform, encoding, language and name ids in req
1170 * and if the name exists the function will fill in the string
1171 * and string_len members. The string is owned by FreeType so
1172 * don't free it. Returns TRUE if the name is found else FALSE.
1174 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1177 FT_UInt num_names, name_index;
1179 if(FT_IS_SFNT(ft_face))
1181 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1183 for(name_index = 0; name_index < num_names; name_index++)
1185 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1187 if((name.platform_id == req->platform_id) &&
1188 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1189 (name.language_id == req->language_id) &&
1190 (name.name_id == req->name_id))
1192 req->string = name.string;
1193 req->string_len = name.string_len;
1200 req->string_len = 0;
1204 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1209 name.platform_id = TT_PLATFORM_MICROSOFT;
1210 name.language_id = language_id;
1211 name.name_id = name_id;
1213 if(get_name_table_entry(ft_face, &name))
1217 /* String is not nul terminated and string_len is a byte length. */
1218 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1219 for(i = 0; i < name.string_len / 2; i++)
1221 WORD *tmp = (WORD *)&name.string[i * 2];
1222 ret[i] = GET_BE_WORD(*tmp);
1225 TRACE("Got localised name %s\n", debugstr_w(ret));
1231 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1233 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1234 if (f1->scalable) return TRUE;
1235 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1236 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1239 static inline void free_face( Face *face )
1241 HeapFree( GetProcessHeap(), 0, face->file );
1242 HeapFree( GetProcessHeap(), 0, face->StyleName );
1243 HeapFree( GetProcessHeap(), 0, face->FullName );
1244 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1245 HeapFree( GetProcessHeap(), 0, face );
1248 static inline void free_family( Family *family )
1250 Face *face, *cursor2;
1252 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1254 list_remove( &face->entry );
1257 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1258 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1259 HeapFree( GetProcessHeap(), 0, family );
1262 static inline int style_order(const Face *face)
1264 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1272 case NTM_BOLD | NTM_ITALIC:
1275 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1276 debugstr_w(face->family->FamilyName),
1277 debugstr_w(face->StyleName),
1283 static BOOL insert_face_in_family_list( Face *face, Family *family )
1287 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1289 if (faces_equal( face, cursor ))
1291 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1292 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1293 cursor->font_version, face->font_version);
1295 if (face->font_version <= cursor->font_version)
1297 TRACE("Original font %s is newer so skipping %s\n",
1298 debugstr_w(cursor->file), debugstr_w(face->file));
1303 TRACE("Replacing original %s with %s\n",
1304 debugstr_w(cursor->file), debugstr_w(face->file));
1305 list_add_before( &cursor->entry, &face->entry );
1306 face->family = family;
1307 list_remove( &cursor->entry);
1308 free_face( cursor );
1313 TRACE("Adding new %s\n", debugstr_w(face->file));
1315 if (style_order( face ) < style_order( cursor )) break;
1318 list_add_before( &cursor->entry, &face->entry );
1319 face->family = family;
1323 /****************************************************************
1324 * NB This function stores the ptrs to the strings to save copying.
1325 * Don't free them after calling.
1327 static Family *create_family( WCHAR *name, WCHAR *english_name )
1329 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1330 family->FamilyName = name;
1331 family->EnglishName = english_name;
1332 list_init( &family->faces );
1333 family->replacement = &family->faces;
1338 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1340 DWORD type, size = sizeof(DWORD);
1342 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1343 type != REG_DWORD || size != sizeof(DWORD))
1346 return ERROR_BAD_CONFIGURATION;
1348 return ERROR_SUCCESS;
1351 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1353 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1356 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1358 DWORD needed, strike_index = 0;
1361 /* If we have a File Name key then this is a real font, not just the parent
1362 key of a bunch of non-scalable strikes */
1363 needed = buffer_size;
1364 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1367 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1368 face->cached_enum_data = NULL;
1370 face->file = strdupW( buffer );
1371 face->StyleName = strdupW(face_name);
1373 needed = buffer_size;
1374 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1375 face->FullName = strdupW( buffer );
1377 face->FullName = NULL;
1379 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1380 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1381 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1382 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1383 reg_load_dword(hkey_face, face_aa_value, (DWORD*)&face->aa_flags);
1385 needed = sizeof(face->fs);
1386 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1388 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1390 face->scalable = TRUE;
1391 memset(&face->size, 0, sizeof(face->size));
1395 face->scalable = FALSE;
1396 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1397 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1398 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1399 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1400 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1402 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1403 face->size.height, face->size.width, face->size.size >> 6,
1404 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1407 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1408 face->fs.fsCsb[0], face->fs.fsCsb[1],
1409 face->fs.fsUsb[0], face->fs.fsUsb[1],
1410 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1412 insert_face_in_family_list(face, family);
1414 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1417 /* load bitmap strikes */
1419 needed = buffer_size;
1420 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1422 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1424 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1425 RegCloseKey(hkey_strike);
1427 needed = buffer_size;
1431 static void load_font_list_from_cache(HKEY hkey_font_cache)
1433 DWORD size, family_index = 0;
1438 size = sizeof(buffer);
1439 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1441 WCHAR *english_family = NULL;
1442 WCHAR *family_name = strdupW( buffer );
1443 DWORD face_index = 0;
1445 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1446 TRACE("opened family key %s\n", debugstr_w(family_name));
1447 size = sizeof(buffer);
1448 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1449 english_family = strdupW( buffer );
1451 family = create_family(family_name, english_family);
1452 list_add_tail(&font_list, &family->entry);
1456 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1457 subst->from.name = strdupW(english_family);
1458 subst->from.charset = -1;
1459 subst->to.name = strdupW(family_name);
1460 subst->to.charset = -1;
1461 add_font_subst(&font_subst_list, subst, 0);
1464 size = sizeof(buffer);
1465 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1467 WCHAR *face_name = strdupW( buffer );
1470 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1472 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1473 RegCloseKey(hkey_face);
1475 HeapFree( GetProcessHeap(), 0, face_name );
1476 size = sizeof(buffer);
1478 RegCloseKey(hkey_family);
1479 size = sizeof(buffer);
1483 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1486 HKEY hkey_wine_fonts;
1488 /* We don't want to create the fonts key as volatile, so open this first */
1489 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1490 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1491 if(ret != ERROR_SUCCESS)
1493 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1497 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1498 KEY_ALL_ACCESS, NULL, hkey, disposition);
1499 RegCloseKey(hkey_wine_fonts);
1503 static void add_face_to_cache(Face *face)
1505 HKEY hkey_font_cache, hkey_family, hkey_face;
1506 WCHAR *face_key_name;
1508 create_font_cache_key(&hkey_font_cache, NULL);
1510 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1511 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1512 if(face->family->EnglishName)
1513 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1514 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1517 face_key_name = face->StyleName;
1520 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1521 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1522 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1524 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1527 HeapFree(GetProcessHeap(), 0, face_key_name);
1529 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1530 (strlenW(face->file) + 1) * sizeof(WCHAR));
1532 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1533 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1535 reg_save_dword(hkey_face, face_index_value, face->face_index);
1536 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1537 reg_save_dword(hkey_face, face_version_value, face->font_version);
1538 if (face->vertical) reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1539 if (face->aa_flags) reg_save_dword(hkey_face, face_aa_value, face->aa_flags);
1541 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1545 reg_save_dword(hkey_face, face_height_value, face->size.height);
1546 reg_save_dword(hkey_face, face_width_value, face->size.width);
1547 reg_save_dword(hkey_face, face_size_value, face->size.size);
1548 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1549 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1550 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1552 RegCloseKey(hkey_face);
1553 RegCloseKey(hkey_family);
1554 RegCloseKey(hkey_font_cache);
1557 static WCHAR *prepend_at(WCHAR *family)
1564 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1566 strcpyW(str + 1, family);
1567 HeapFree(GetProcessHeap(), 0, family);
1571 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1573 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1574 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1576 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1582 else if (!strcmpiW( *name, *english ))
1584 HeapFree( GetProcessHeap(), 0, *english );
1590 *name = prepend_at( *name );
1591 *english = prepend_at( *english );
1595 static Family *get_family( FT_Face ft_face, BOOL vertical )
1598 WCHAR *name, *english_name;
1600 get_family_names( ft_face, &name, &english_name, vertical );
1602 family = find_family_from_name( name );
1606 family = create_family( name, english_name );
1607 list_add_tail( &font_list, &family->entry );
1611 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1612 subst->from.name = strdupW( english_name );
1613 subst->from.charset = -1;
1614 subst->to.name = strdupW( name );
1615 subst->to.charset = -1;
1616 add_font_subst( &font_subst_list, subst, 0 );
1621 HeapFree( GetProcessHeap(), 0, name );
1622 HeapFree( GetProcessHeap(), 0, english_name );
1628 static inline FT_Fixed get_font_version( FT_Face ft_face )
1630 FT_Fixed version = 0;
1633 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1634 if (header) version = header->Font_Revision;
1639 static inline DWORD get_ntm_flags( FT_Face ft_face )
1642 FT_ULong table_size = 0;
1644 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1645 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1646 if (flags == 0) flags = NTM_REGULAR;
1648 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1649 flags |= NTM_PS_OPENTYPE;
1654 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1656 int internal_leading = 0;
1657 FT_WinFNT_HeaderRec winfnt_header;
1659 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1660 internal_leading = winfnt_header.internal_leading;
1662 return internal_leading;
1665 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1670 FT_WinFNT_HeaderRec winfnt_header;
1673 memset( fs, 0, sizeof(*fs) );
1675 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1678 fs->fsUsb[0] = os2->ulUnicodeRange1;
1679 fs->fsUsb[1] = os2->ulUnicodeRange2;
1680 fs->fsUsb[2] = os2->ulUnicodeRange3;
1681 fs->fsUsb[3] = os2->ulUnicodeRange4;
1683 if (os2->version == 0)
1685 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1686 fs->fsCsb[0] = FS_LATIN1;
1688 fs->fsCsb[0] = FS_SYMBOL;
1692 fs->fsCsb[0] = os2->ulCodePageRange1;
1693 fs->fsCsb[1] = os2->ulCodePageRange2;
1698 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1700 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1701 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1702 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1707 if (fs->fsCsb[0] == 0)
1709 /* let's see if we can find any interesting cmaps */
1710 for (i = 0; i < ft_face->num_charmaps; i++)
1712 switch (ft_face->charmaps[i]->encoding)
1714 case FT_ENCODING_UNICODE:
1715 case FT_ENCODING_APPLE_ROMAN:
1716 fs->fsCsb[0] |= FS_LATIN1;
1718 case FT_ENCODING_MS_SYMBOL:
1719 fs->fsCsb[0] |= FS_SYMBOL;
1728 #define ADDFONT_EXTERNAL_FONT 0x01
1729 #define ADDFONT_FORCE_BITMAP 0x02
1730 #define ADDFONT_ADD_TO_CACHE 0x04
1731 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
1733 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1734 DWORD flags, BOOL vertical, DWORD aa_flags )
1736 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1737 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1739 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1740 if (!face->StyleName)
1741 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1742 if (!face->StyleName)
1744 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1747 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1748 if (!face->FullName)
1749 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1751 face->FullName = prepend_at( face->FullName );
1755 face->file = towstr( CP_UNIXCP, file );
1756 face->font_data_ptr = NULL;
1757 face->font_data_size = 0;
1762 face->font_data_ptr = font_data_ptr;
1763 face->font_data_size = font_data_size;
1766 face->face_index = face_index;
1767 get_fontsig( ft_face, &face->fs );
1768 face->ntmFlags = get_ntm_flags( ft_face );
1769 face->font_version = get_font_version( ft_face );
1771 if (FT_IS_SCALABLE( ft_face ))
1773 memset( &face->size, 0, sizeof(face->size) );
1774 face->scalable = TRUE;
1778 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1779 size->height, size->width, size->size >> 6,
1780 size->x_ppem >> 6, size->y_ppem >> 6);
1781 face->size.height = size->height;
1782 face->size.width = size->width;
1783 face->size.size = size->size;
1784 face->size.x_ppem = size->x_ppem;
1785 face->size.y_ppem = size->y_ppem;
1786 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1787 face->scalable = FALSE;
1790 face->vertical = vertical;
1791 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1792 face->aa_flags = aa_flags;
1793 face->family = NULL;
1794 face->cached_enum_data = NULL;
1796 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1797 face->fs.fsCsb[0], face->fs.fsCsb[1],
1798 face->fs.fsUsb[0], face->fs.fsUsb[1],
1799 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1804 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1805 FT_Long face_index, DWORD flags, BOOL vertical, DWORD aa_flags )
1810 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical, aa_flags );
1811 family = get_family( ft_face, vertical );
1812 if (!insert_face_in_family_list( face, family ))
1818 if (flags & ADDFONT_ADD_TO_CACHE)
1819 add_face_to_cache( face );
1821 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1822 debugstr_w(face->StyleName));
1825 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1826 FT_Long face_index, BOOL allow_bitmap )
1834 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1835 err = pFT_New_Face(library, file, face_index, &ft_face);
1839 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1840 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1845 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1849 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1850 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1852 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1856 if (!FT_IS_SFNT( ft_face ))
1858 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1860 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1866 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1867 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1868 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1870 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1871 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1875 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1876 we don't want to load these. */
1877 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1881 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1883 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1889 if (!ft_face->family_name || !ft_face->style_name)
1891 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1897 pFT_Done_Face( ft_face );
1901 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1904 FT_Long face_index = 0, num_faces;
1906 DWORD aa_flags = HIWORD( flags );
1908 if (!aa_flags) aa_flags = default_aa_flags;
1910 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1911 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1913 #ifdef HAVE_CARBON_CARBON_H
1916 char **mac_list = expand_mac_font(file);
1919 BOOL had_one = FALSE;
1921 for(cursor = mac_list; *cursor; cursor++)
1924 AddFontToList(*cursor, NULL, 0, flags);
1925 HeapFree(GetProcessHeap(), 0, *cursor);
1927 HeapFree(GetProcessHeap(), 0, mac_list);
1932 #endif /* HAVE_CARBON_CARBON_H */
1935 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1936 if (!ft_face) return 0;
1938 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1940 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1941 pFT_Done_Face(ft_face);
1945 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE, aa_flags);
1948 if (FT_HAS_VERTICAL(ft_face))
1950 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE, aa_flags);
1954 num_faces = ft_face->num_faces;
1955 pFT_Done_Face(ft_face);
1956 } while(num_faces > ++face_index);
1960 static void DumpFontList(void)
1964 struct list *family_elem_ptr, *face_elem_ptr;
1966 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1967 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1968 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1969 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1970 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1971 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1973 TRACE(" %d", face->size.height);
1980 /***********************************************************
1981 * The replacement list is a way to map an entire font
1982 * family onto another family. For example adding
1984 * [HKCU\Software\Wine\Fonts\Replacements]
1985 * "Wingdings"="Winedings"
1987 * would enumerate the Winedings font both as Winedings and
1988 * Wingdings. However if a real Wingdings font is present the
1989 * replacement does not take place.
1992 static void LoadReplaceList(void)
1995 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1999 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2000 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2002 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2003 &valuelen, &datalen, NULL, NULL);
2005 valuelen++; /* returned value doesn't include room for '\0' */
2006 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2007 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2011 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2012 &dlen) == ERROR_SUCCESS) {
2013 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2014 /* "NewName"="Oldname" */
2015 if(!find_family_from_any_name(value))
2017 Family * const family = find_family_from_any_name(data);
2020 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2021 if (new_family != NULL)
2023 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2024 new_family->FamilyName = strdupW(value);
2025 new_family->EnglishName = NULL;
2026 list_init(&new_family->faces);
2027 new_family->replacement = &family->faces;
2028 list_add_tail(&font_list, &new_family->entry);
2033 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2038 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2040 /* reset dlen and vlen */
2044 HeapFree(GetProcessHeap(), 0, data);
2045 HeapFree(GetProcessHeap(), 0, value);
2050 static const WCHAR *font_links_list[] =
2052 Lucida_Sans_Unicode,
2053 Microsoft_Sans_Serif,
2057 static const struct font_links_defaults_list
2059 /* Keyed off substitution for "MS Shell Dlg" */
2060 const WCHAR *shelldlg;
2061 /* Maximum of four substitutes, plus terminating NULL pointer */
2062 const WCHAR *substitutes[5];
2063 } font_links_defaults_list[] =
2065 /* Non East-Asian */
2066 { Tahoma, /* FIXME unverified ordering */
2067 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2069 /* Below lists are courtesy of
2070 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2074 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2076 /* Chinese Simplified */
2078 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2082 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2084 /* Chinese Traditional */
2086 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2091 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2093 SYSTEM_LINKS *font_link;
2095 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2097 if(!strcmpiW(font_link->font_name, name))
2104 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2115 SYSTEM_LINKS *font_link;
2117 psub = get_font_subst(&font_subst_list, name, -1);
2118 /* Don't store fonts that are only substitutes for other fonts */
2121 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2125 font_link = find_font_link(name);
2126 if (font_link == NULL)
2128 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2129 font_link->font_name = strdupW(name);
2130 list_init(&font_link->links);
2131 list_add_tail(&system_links, &font_link->entry);
2134 memset(&font_link->fs, 0, sizeof font_link->fs);
2135 for (i = 0; values[i] != NULL; i++)
2137 const struct list *face_list;
2138 CHILD_FONT *child_font;
2141 if (!strcmpiW(name,value))
2143 psub = get_font_subst(&font_subst_list, value, -1);
2145 value = psub->to.name;
2146 family = find_family_from_name(value);
2150 /* Use first extant filename for this Family */
2151 face_list = get_face_list_from_family(family);
2152 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2156 file = strrchrW(face->file, '/');
2165 face = find_face_from_filename(file, value);
2168 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2172 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2173 child_font->face = face;
2174 child_font->font = NULL;
2175 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2176 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2177 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2178 child_font->face->face_index);
2179 list_add_tail(&font_link->links, &child_font->entry);
2181 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2187 /*************************************************************
2190 static BOOL init_system_links(void)
2194 DWORD type, max_val, max_data, val_len, data_len, index;
2195 WCHAR *value, *data;
2196 WCHAR *entry, *next;
2197 SYSTEM_LINKS *font_link, *system_font_link;
2198 CHILD_FONT *child_font;
2199 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2200 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2201 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2206 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2208 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2209 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2210 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2211 val_len = max_val + 1;
2212 data_len = max_data;
2214 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2216 psub = get_font_subst(&font_subst_list, value, -1);
2217 /* Don't store fonts that are only substitutes for other fonts */
2220 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2223 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2224 font_link->font_name = strdupW(value);
2225 memset(&font_link->fs, 0, sizeof font_link->fs);
2226 list_init(&font_link->links);
2227 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2230 CHILD_FONT *child_font;
2232 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2234 next = entry + strlenW(entry) + 1;
2236 face_name = strchrW(entry, ',');
2240 while(isspaceW(*face_name))
2243 psub = get_font_subst(&font_subst_list, face_name, -1);
2245 face_name = psub->to.name;
2247 face = find_face_from_filename(entry, face_name);
2250 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2254 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2255 child_font->face = face;
2256 child_font->font = NULL;
2257 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2258 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2259 TRACE("Adding file %s index %ld\n",
2260 debugstr_w(child_font->face->file), child_font->face->face_index);
2261 list_add_tail(&font_link->links, &child_font->entry);
2263 list_add_tail(&system_links, &font_link->entry);
2265 val_len = max_val + 1;
2266 data_len = max_data;
2269 HeapFree(GetProcessHeap(), 0, value);
2270 HeapFree(GetProcessHeap(), 0, data);
2275 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2277 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2281 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2283 const FontSubst *psub2;
2284 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2286 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2288 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2289 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2291 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2292 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2294 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2296 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2302 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2305 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2306 system_font_link->font_name = strdupW(System);
2307 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2308 list_init(&system_font_link->links);
2310 face = find_face_from_filename(tahoma_ttf, Tahoma);
2313 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2314 child_font->face = face;
2315 child_font->font = NULL;
2316 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2317 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2318 TRACE("Found Tahoma in %s index %ld\n",
2319 debugstr_w(child_font->face->file), child_font->face->face_index);
2320 list_add_tail(&system_font_link->links, &child_font->entry);
2322 font_link = find_font_link(Tahoma);
2323 if (font_link != NULL)
2325 CHILD_FONT *font_link_entry;
2326 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2328 CHILD_FONT *new_child;
2329 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2330 new_child->face = font_link_entry->face;
2331 new_child->font = NULL;
2332 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2333 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2334 list_add_tail(&system_font_link->links, &new_child->entry);
2337 list_add_tail(&system_links, &system_font_link->entry);
2341 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2344 struct dirent *dent;
2345 char path[MAX_PATH];
2347 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2349 dir = opendir(dirname);
2351 WARN("Can't open directory %s\n", debugstr_a(dirname));
2354 while((dent = readdir(dir)) != NULL) {
2355 struct stat statbuf;
2357 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2360 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2362 sprintf(path, "%s/%s", dirname, dent->d_name);
2364 if(stat(path, &statbuf) == -1)
2366 WARN("Can't stat %s\n", debugstr_a(path));
2369 if(S_ISDIR(statbuf.st_mode))
2370 ReadFontDir(path, external_fonts);
2373 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2374 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2375 AddFontToList(path, NULL, 0, addfont_flags);
2382 #ifdef SONAME_LIBFONTCONFIG
2384 static BOOL fontconfig_enabled;
2386 static UINT parse_aa_pattern( FcPattern *pattern )
2392 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2393 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2395 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2399 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2400 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2401 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2402 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2403 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2409 static void init_fontconfig(void)
2411 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2415 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2419 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2420 LOAD_FUNCPTR(FcConfigSubstitute);
2421 LOAD_FUNCPTR(FcFontList);
2422 LOAD_FUNCPTR(FcFontSetDestroy);
2423 LOAD_FUNCPTR(FcInit);
2424 LOAD_FUNCPTR(FcObjectSetAdd);
2425 LOAD_FUNCPTR(FcObjectSetCreate);
2426 LOAD_FUNCPTR(FcObjectSetDestroy);
2427 LOAD_FUNCPTR(FcPatternCreate);
2428 LOAD_FUNCPTR(FcPatternDestroy);
2429 LOAD_FUNCPTR(FcPatternGetBool);
2430 LOAD_FUNCPTR(FcPatternGetInteger);
2431 LOAD_FUNCPTR(FcPatternGetString);
2436 FcPattern *pattern = pFcPatternCreate();
2437 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2438 default_aa_flags = parse_aa_pattern( pattern );
2439 pFcPatternDestroy( pattern );
2440 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2441 fontconfig_enabled = TRUE;
2445 static void load_fontconfig_fonts(void)
2454 if (!fontconfig_enabled) return;
2456 pat = pFcPatternCreate();
2457 os = pFcObjectSetCreate();
2458 pFcObjectSetAdd(os, FC_FILE);
2459 pFcObjectSetAdd(os, FC_SCALABLE);
2460 pFcObjectSetAdd(os, FC_ANTIALIAS);
2461 pFcObjectSetAdd(os, FC_RGBA);
2462 fontset = pFcFontList(NULL, pat, os);
2463 if(!fontset) return;
2464 for(i = 0; i < fontset->nfont; i++) {
2468 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2471 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2473 /* We're just interested in OT/TT fonts for now, so this hack just
2474 picks up the scalable fonts without extensions .pf[ab] to save time
2475 loading every other font */
2477 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2479 TRACE("not scalable\n");
2483 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2484 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2486 len = strlen( file );
2487 if(len < 4) continue;
2488 ext = &file[ len - 3 ];
2489 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2490 AddFontToList(file, NULL, 0,
2491 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2493 pFcFontSetDestroy(fontset);
2494 pFcObjectSetDestroy(os);
2495 pFcPatternDestroy(pat);
2498 #elif defined(HAVE_CARBON_CARBON_H)
2500 static void load_mac_font_callback(const void *value, void *context)
2502 CFStringRef pathStr = value;
2506 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2507 path = HeapAlloc(GetProcessHeap(), 0, len);
2508 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2510 TRACE("font file %s\n", path);
2511 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2513 HeapFree(GetProcessHeap(), 0, path);
2516 static void load_mac_fonts(void)
2518 CFStringRef removeDupesKey;
2519 CFBooleanRef removeDupesValue;
2520 CFDictionaryRef options;
2521 CTFontCollectionRef col;
2523 CFMutableSetRef paths;
2526 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2527 removeDupesValue = kCFBooleanTrue;
2528 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2529 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2530 col = CTFontCollectionCreateFromAvailableFonts(options);
2531 if (options) CFRelease(options);
2534 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2538 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2542 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2546 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2549 WARN("CFSetCreateMutable failed\n");
2554 for (i = 0; i < CFArrayGetCount(descs); i++)
2556 CTFontDescriptorRef desc;
2565 desc = CFArrayGetValueAtIndex(descs, i);
2567 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2568 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2569 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2570 if (!font) continue;
2572 atsFont = CTFontGetPlatformFont(font, NULL);
2579 status = ATSFontGetFileReference(atsFont, &fsref);
2581 if (status != noErr) continue;
2583 url = CFURLCreateFromFSRef(NULL, &fsref);
2586 ext = CFURLCopyPathExtension(url);
2589 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2590 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2599 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2601 if (!path) continue;
2603 CFSetAddValue(paths, path);
2609 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2615 static BOOL load_font_from_data_dir(LPCWSTR file)
2618 const char *data_dir = wine_get_data_dir();
2620 if (!data_dir) data_dir = wine_get_build_dir();
2627 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2629 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2631 strcpy(unix_name, data_dir);
2632 strcat(unix_name, "/fonts/");
2634 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2636 EnterCriticalSection( &freetype_cs );
2637 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2638 LeaveCriticalSection( &freetype_cs );
2639 HeapFree(GetProcessHeap(), 0, unix_name);
2644 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2646 static const WCHAR slashW[] = {'\\','\0'};
2648 WCHAR windowsdir[MAX_PATH];
2651 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2652 strcatW(windowsdir, fontsW);
2653 strcatW(windowsdir, slashW);
2654 strcatW(windowsdir, file);
2655 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2656 EnterCriticalSection( &freetype_cs );
2657 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2658 LeaveCriticalSection( &freetype_cs );
2659 HeapFree(GetProcessHeap(), 0, unixname);
2664 static void load_system_fonts(void)
2667 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2668 const WCHAR * const *value;
2670 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2673 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2674 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2675 strcatW(windowsdir, fontsW);
2676 for(value = SystemFontValues; *value; value++) {
2677 dlen = sizeof(data);
2678 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2682 sprintfW(pathW, fmtW, windowsdir, data);
2683 if((unixname = wine_get_unix_file_name(pathW))) {
2684 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2685 HeapFree(GetProcessHeap(), 0, unixname);
2688 load_font_from_data_dir(data);
2695 /*************************************************************
2697 * This adds registry entries for any externally loaded fonts
2698 * (fonts from fontconfig or FontDirs). It also deletes entries
2699 * of no longer existing fonts.
2702 static void update_reg_entries(void)
2704 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2709 struct list *family_elem_ptr, *face_elem_ptr;
2711 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2713 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2714 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2715 ERR("Can't create Windows font reg key\n");
2719 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2720 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2721 ERR("Can't create Windows font reg key\n");
2725 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2726 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2727 ERR("Can't create external font reg key\n");
2731 /* enumerate the fonts and add external ones to the two keys */
2733 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2734 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2735 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2737 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2738 if(!face->external) continue;
2742 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2743 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2744 strcpyW(valueW, face->FullName);
2748 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2749 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2750 strcpyW(valueW, family->FamilyName);
2753 buffer = strWtoA( CP_UNIXCP, face->file );
2754 path = wine_get_dos_file_name( buffer );
2755 HeapFree( GetProcessHeap(), 0, buffer );
2759 else if ((file = strrchrW(face->file, '/')))
2764 len = strlenW(file) + 1;
2765 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2766 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2767 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2769 HeapFree(GetProcessHeap(), 0, path);
2770 HeapFree(GetProcessHeap(), 0, valueW);
2774 if(external_key) RegCloseKey(external_key);
2775 if(win9x_key) RegCloseKey(win9x_key);
2776 if(winnt_key) RegCloseKey(winnt_key);
2780 static void delete_external_font_keys(void)
2782 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2783 DWORD dlen, vlen, datalen, valuelen, i, type;
2787 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2788 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2789 ERR("Can't create Windows font reg key\n");
2793 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2794 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2795 ERR("Can't create Windows font reg key\n");
2799 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2800 ERR("Can't create external font reg key\n");
2804 /* Delete all external fonts added last time */
2806 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2807 &valuelen, &datalen, NULL, NULL);
2808 valuelen++; /* returned value doesn't include room for '\0' */
2809 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2810 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2812 dlen = datalen * sizeof(WCHAR);
2815 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2816 &dlen) == ERROR_SUCCESS) {
2818 RegDeleteValueW(winnt_key, valueW);
2819 RegDeleteValueW(win9x_key, valueW);
2820 /* reset dlen and vlen */
2824 HeapFree(GetProcessHeap(), 0, data);
2825 HeapFree(GetProcessHeap(), 0, valueW);
2827 /* Delete the old external fonts key */
2828 RegCloseKey(external_key);
2829 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2832 if(win9x_key) RegCloseKey(win9x_key);
2833 if(winnt_key) RegCloseKey(winnt_key);
2836 /*************************************************************
2837 * WineEngAddFontResourceEx
2840 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2846 if (ft_handle) /* do it only if we have freetype up and running */
2851 FIXME("Ignoring flags %x\n", flags);
2853 if((unixname = wine_get_unix_file_name(file)))
2855 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2857 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2858 EnterCriticalSection( &freetype_cs );
2859 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2860 LeaveCriticalSection( &freetype_cs );
2861 HeapFree(GetProcessHeap(), 0, unixname);
2863 if (!ret && !strchrW(file, '\\')) {
2864 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2865 ret = load_font_from_winfonts_dir(file);
2867 /* Try in datadir/fonts (or builddir/fonts),
2868 * needed for Magic the Gathering Online
2870 ret = load_font_from_data_dir(file);
2877 /*************************************************************
2878 * WineEngAddFontMemResourceEx
2881 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2885 if (ft_handle) /* do it only if we have freetype up and running */
2887 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2889 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2890 memcpy(pFontCopy, pbFont, cbFont);
2892 EnterCriticalSection( &freetype_cs );
2893 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2894 LeaveCriticalSection( &freetype_cs );
2898 TRACE("AddFontToList failed\n");
2899 HeapFree(GetProcessHeap(), 0, pFontCopy);
2902 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2903 * For now return something unique but quite random
2905 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2906 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2913 /*************************************************************
2914 * WineEngRemoveFontResourceEx
2917 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2920 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2924 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2930 if (!font_file) return NULL;
2932 file_len = strlenW( font_file );
2934 if (font_path && font_path[0])
2936 int path_len = strlenW( font_path );
2937 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2938 if (!fullname) return NULL;
2939 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2940 fullname[path_len] = '\\';
2941 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2945 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2946 if (!len) return NULL;
2947 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2948 if (!fullname) return NULL;
2949 GetFullPathNameW( font_file, len, fullname, NULL );
2952 unix_name = wine_get_unix_file_name( fullname );
2953 HeapFree( GetProcessHeap(), 0, fullname );
2957 #include <pshpack1.h>
2960 WORD num_of_resources;
2964 CHAR dfCopyright[60];
2970 WORD dfInternalLeading;
2971 WORD dfExternalLeading;
2979 BYTE dfPitchAndFamily;
2990 CHAR szFaceName[LF_FACESIZE];
2993 #include <poppack.h>
2995 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2996 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2998 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3000 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3003 WCHAR *name, *english_name;
3005 NEWTEXTMETRICEXW ntm;
3008 if (!ft_face) return FALSE;
3009 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE, 0 );
3010 get_family_names( ft_face, &name, &english_name, FALSE );
3011 family = create_family( name, english_name );
3012 insert_face_in_family_list( face, family );
3013 pFT_Done_Face( ft_face );
3015 GetEnumStructs( face, &elf, &ntm, &type );
3016 free_family( family );
3018 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3020 memset( fd, 0, sizeof(*fd) );
3022 fd->num_of_resources = 1;
3024 fd->dfVersion = 0x200;
3025 fd->dfSize = sizeof(*fd);
3026 strcpy( fd->dfCopyright, "Wine fontdir" );
3027 fd->dfType = 0x4003; /* 0x0080 set if private */
3028 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3030 fd->dfHorizRes = 72;
3031 fd->dfAscent = ntm.ntmTm.tmAscent;
3032 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3033 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3034 fd->dfItalic = ntm.ntmTm.tmItalic;
3035 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3036 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3037 fd->dfWeight = ntm.ntmTm.tmWeight;
3038 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3040 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3041 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3042 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3043 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3044 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3045 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3046 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3047 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3048 fd->dfWidthBytes = 0;
3050 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3052 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3057 #define NE_FFLAGS_LIBMODULE 0x8000
3058 #define NE_OSFLAGS_WINDOWS 0x02
3060 static const char dos_string[0x40] = "This is a TrueType resource file";
3061 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3063 #include <pshpack2.h>
3084 struct ne_typeinfo fontdir_type;
3085 struct ne_nameinfo fontdir_name;
3086 struct ne_typeinfo scalable_type;
3087 struct ne_nameinfo scalable_name;
3089 BYTE fontdir_res_name[8];
3092 #include <poppack.h>
3094 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3098 DWORD size, written;
3100 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3101 char *font_fileA, *last_part, *ext;
3102 IMAGE_DOS_HEADER dos;
3103 IMAGE_OS2_HEADER ne =
3105 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3107 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3108 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3110 struct rsrc_tab rsrc_tab =
3114 { 0, 0, 0x0c50, 0x2c, 0 },
3116 { 0, 0, 0x0c50, 0x8001, 0 },
3118 { 7,'F','O','N','T','D','I','R'}
3121 memset( &dos, 0, sizeof(dos) );
3122 dos.e_magic = IMAGE_DOS_SIGNATURE;
3123 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3125 /* import name is last part\0, resident name is last part without extension
3126 non-resident name is "FONTRES:" + lfFaceName */
3128 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3129 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3130 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3132 last_part = strrchr( font_fileA, '\\' );
3133 if (last_part) last_part++;
3134 else last_part = font_fileA;
3135 import_name_len = strlen( last_part ) + 1;
3137 ext = strchr( last_part, '.' );
3138 if (ext) res_name_len = ext - last_part;
3139 else res_name_len = import_name_len - 1;
3141 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3143 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3144 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3145 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3146 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3148 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3150 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3151 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3152 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3153 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3155 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3156 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3160 HeapFree( GetProcessHeap(), 0, font_fileA );
3164 memcpy( ptr, &dos, sizeof(dos) );
3165 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3166 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3168 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3169 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3171 ptr = start + dos.e_lfanew + ne.ne_restab;
3172 *ptr++ = res_name_len;
3173 memcpy( ptr, last_part, res_name_len );
3175 ptr = start + dos.e_lfanew + ne.ne_imptab;
3176 *ptr++ = import_name_len;
3177 memcpy( ptr, last_part, import_name_len );
3179 ptr = start + ne.ne_nrestab;
3180 *ptr++ = non_res_name_len;
3181 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3182 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3184 ptr = start + (rsrc_tab.scalable_name.off << 4);
3185 memcpy( ptr, font_fileA, font_file_len );
3187 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3188 memcpy( ptr, fontdir, fontdir->dfSize );
3190 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3191 if (file != INVALID_HANDLE_VALUE)
3193 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3195 CloseHandle( file );
3198 HeapFree( GetProcessHeap(), 0, start );
3199 HeapFree( GetProcessHeap(), 0, font_fileA );
3204 /*************************************************************
3205 * WineEngCreateScalableFontResource
3208 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3209 LPCWSTR font_file, LPCWSTR font_path )
3211 char *unix_name = get_ttf_file_name( font_file, font_path );
3212 struct fontdir fontdir;
3215 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3216 SetLastError( ERROR_INVALID_PARAMETER );
3219 if (hidden) fontdir.dfType |= 0x80;
3220 ret = create_fot( resource, font_file, &fontdir );
3223 HeapFree( GetProcessHeap(), 0, unix_name );
3227 static const struct nls_update_font_list
3229 UINT ansi_cp, oem_cp;
3230 const char *oem, *fixed, *system;
3231 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3232 /* these are for font substitutes */
3233 const char *shelldlg, *tmsrmn;
3234 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3238 const char *from, *to;
3239 } arial_0, courier_new_0, times_new_roman_0;
3240 } nls_update_font_list[] =
3242 /* Latin 1 (United States) */
3243 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3244 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3245 "Tahoma","Times New Roman",
3246 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3249 /* Latin 1 (Multilingual) */
3250 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3251 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3252 "Tahoma","Times New Roman", /* FIXME unverified */
3253 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3256 /* Eastern Europe */
3257 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3258 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3259 "Tahoma","Times New Roman", /* FIXME unverified */
3260 "Fixedsys,238", "System,238",
3261 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3262 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3263 { "Arial CE,0", "Arial,238" },
3264 { "Courier New CE,0", "Courier New,238" },
3265 { "Times New Roman CE,0", "Times New Roman,238" }
3268 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3269 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3270 "Tahoma","Times New Roman", /* FIXME unverified */
3271 "Fixedsys,204", "System,204",
3272 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3273 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3274 { "Arial Cyr,0", "Arial,204" },
3275 { "Courier New Cyr,0", "Courier New,204" },
3276 { "Times New Roman Cyr,0", "Times New Roman,204" }
3279 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3280 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3281 "Tahoma","Times New Roman", /* FIXME unverified */
3282 "Fixedsys,161", "System,161",
3283 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3284 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3285 { "Arial Greek,0", "Arial,161" },
3286 { "Courier New Greek,0", "Courier New,161" },
3287 { "Times New Roman Greek,0", "Times New Roman,161" }
3290 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3291 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3292 "Tahoma","Times New Roman", /* FIXME unverified */
3293 "Fixedsys,162", "System,162",
3294 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3295 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3296 { "Arial Tur,0", "Arial,162" },
3297 { "Courier New Tur,0", "Courier New,162" },
3298 { "Times New Roman Tur,0", "Times New Roman,162" }
3301 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3302 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3303 "Tahoma","Times New Roman", /* FIXME unverified */
3304 "Fixedsys,177", "System,177",
3305 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3306 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3310 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3311 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3312 "Tahoma","Times New Roman", /* FIXME unverified */
3313 "Fixedsys,178", "System,178",
3314 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3315 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3319 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3320 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3321 "Tahoma","Times New Roman", /* FIXME unverified */
3322 "Fixedsys,186", "System,186",
3323 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3324 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3325 { "Arial Baltic,0", "Arial,186" },
3326 { "Courier New Baltic,0", "Courier New,186" },
3327 { "Times New Roman Baltic,0", "Times New Roman,186" }
3330 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3331 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3332 "Tahoma","Times New Roman", /* FIXME unverified */
3333 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3337 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3338 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3339 "Tahoma","Times New Roman", /* FIXME unverified */
3340 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3344 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3345 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3346 "MS UI Gothic","MS Serif",
3347 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3350 /* Chinese Simplified */
3351 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3352 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3353 "SimSun", "NSimSun",
3354 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3358 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3359 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3361 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3364 /* Chinese Traditional */
3365 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3366 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3367 "PMingLiU", "MingLiU",
3368 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3373 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3375 return ( ansi_cp == 932 /* CP932 for Japanese */
3376 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3377 || ansi_cp == 949 /* CP949 for Korean */
3378 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3381 static inline HKEY create_fonts_NT_registry_key(void)
3385 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3386 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3390 static inline HKEY create_fonts_9x_registry_key(void)
3394 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3395 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3399 static inline HKEY create_config_fonts_registry_key(void)
3403 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3404 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3408 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3410 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3412 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3413 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3414 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3415 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3418 static void set_value_key(HKEY hkey, const char *name, const char *value)
3421 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3423 RegDeleteValueA(hkey, name);
3426 static void update_font_info(void)
3428 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3429 char buf[40], cpbuf[40];
3432 UINT i, ansi_cp = 0, oem_cp = 0;
3433 DWORD screen_dpi = 96, font_dpi = 0;
3436 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3437 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3438 &hkey) == ERROR_SUCCESS)
3440 reg_load_dword(hkey, logpixels, &screen_dpi);
3444 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3447 reg_load_dword(hkey, logpixels, &font_dpi);
3449 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3450 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3451 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3452 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3453 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3455 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3456 if (is_dbcs_ansi_cp(ansi_cp))
3457 use_default_fallback = TRUE;
3460 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3462 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3467 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3468 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3470 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3471 ansi_cp, oem_cp, screen_dpi);
3473 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3474 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3477 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3481 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3482 nls_update_font_list[i].oem_cp == oem_cp)
3484 hkey = create_config_fonts_registry_key();
3485 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3486 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3487 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3490 hkey = create_fonts_NT_registry_key();
3491 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3494 hkey = create_fonts_9x_registry_key();
3495 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3498 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3500 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3501 strlen(nls_update_font_list[i].shelldlg)+1);
3502 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3503 strlen(nls_update_font_list[i].tmsrmn)+1);
3505 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3506 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3507 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3508 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3509 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3510 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3511 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3512 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3514 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3515 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3516 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3524 /* Delete the FontSubstitutes from other locales */
3525 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3527 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3528 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3529 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3535 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3538 static BOOL init_freetype(void)
3540 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3543 "Wine cannot find the FreeType font library. To enable Wine to\n"
3544 "use TrueType fonts please install a version of FreeType greater than\n"
3545 "or equal to 2.0.5.\n"
3546 "http://www.freetype.org\n");
3550 #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;}
3552 LOAD_FUNCPTR(FT_Done_Face)
3553 LOAD_FUNCPTR(FT_Get_Char_Index)
3554 LOAD_FUNCPTR(FT_Get_First_Char)
3555 LOAD_FUNCPTR(FT_Get_Module)
3556 LOAD_FUNCPTR(FT_Get_Next_Char)
3557 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3558 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3559 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3560 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3561 LOAD_FUNCPTR(FT_Init_FreeType)
3562 LOAD_FUNCPTR(FT_Library_Version)
3563 LOAD_FUNCPTR(FT_Load_Glyph)
3564 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3565 LOAD_FUNCPTR(FT_Matrix_Multiply)
3566 #ifndef FT_MULFIX_INLINED
3567 LOAD_FUNCPTR(FT_MulFix)
3569 LOAD_FUNCPTR(FT_New_Face)
3570 LOAD_FUNCPTR(FT_New_Memory_Face)
3571 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3572 LOAD_FUNCPTR(FT_Outline_Transform)
3573 LOAD_FUNCPTR(FT_Outline_Translate)
3574 LOAD_FUNCPTR(FT_Render_Glyph)
3575 LOAD_FUNCPTR(FT_Select_Charmap)
3576 LOAD_FUNCPTR(FT_Set_Charmap)
3577 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3578 LOAD_FUNCPTR(FT_Vector_Transform)
3579 LOAD_FUNCPTR(FT_Vector_Unit)
3581 /* Don't warn if these ones are missing */
3582 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3583 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3584 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3587 if(pFT_Init_FreeType(&library) != 0) {
3588 ERR("Can't init FreeType library\n");
3589 wine_dlclose(ft_handle, NULL, 0);
3593 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3595 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3596 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3597 ((FT_Version.minor << 8) & 0x00ff00) |
3598 ((FT_Version.patch ) & 0x0000ff);
3600 font_driver = &freetype_funcs;
3605 "Wine cannot find certain functions that it needs inside the FreeType\n"
3606 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3607 "FreeType to at least version 2.1.4.\n"
3608 "http://www.freetype.org\n");
3609 wine_dlclose(ft_handle, NULL, 0);
3614 static void init_font_list(void)
3616 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3617 static const WCHAR pathW[] = {'P','a','t','h',0};
3619 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3620 WCHAR windowsdir[MAX_PATH];
3622 const char *data_dir;
3624 #ifdef SONAME_LIBFONTCONFIG
3628 delete_external_font_keys();
3630 /* load the system bitmap fonts */
3631 load_system_fonts();
3633 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3634 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3635 strcatW(windowsdir, fontsW);
3636 if((unixname = wine_get_unix_file_name(windowsdir)))
3638 ReadFontDir(unixname, FALSE);
3639 HeapFree(GetProcessHeap(), 0, unixname);
3642 /* load the system truetype fonts */
3643 data_dir = wine_get_data_dir();
3644 if (!data_dir) data_dir = wine_get_build_dir();
3645 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3647 strcpy(unixname, data_dir);
3648 strcat(unixname, "/fonts/");
3649 ReadFontDir(unixname, TRUE);
3650 HeapFree(GetProcessHeap(), 0, unixname);
3653 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3654 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3655 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3657 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3658 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3659 &hkey) == ERROR_SUCCESS)
3661 LPWSTR data, valueW;
3662 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3663 &valuelen, &datalen, NULL, NULL);
3665 valuelen++; /* returned value doesn't include room for '\0' */
3666 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3667 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3670 dlen = datalen * sizeof(WCHAR);
3672 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3673 &dlen) == ERROR_SUCCESS)
3675 if(data[0] && (data[1] == ':'))
3677 if((unixname = wine_get_unix_file_name(data)))
3679 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3680 HeapFree(GetProcessHeap(), 0, unixname);
3683 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3685 WCHAR pathW[MAX_PATH];
3686 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3689 sprintfW(pathW, fmtW, windowsdir, data);
3690 if((unixname = wine_get_unix_file_name(pathW)))
3692 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3693 HeapFree(GetProcessHeap(), 0, unixname);
3696 load_font_from_data_dir(data);
3698 /* reset dlen and vlen */
3703 HeapFree(GetProcessHeap(), 0, data);
3704 HeapFree(GetProcessHeap(), 0, valueW);
3708 #ifdef SONAME_LIBFONTCONFIG
3709 load_fontconfig_fonts();
3710 #elif defined(HAVE_CARBON_CARBON_H)
3714 /* then look in any directories that we've specified in the config file */
3715 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3716 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3722 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3724 len += sizeof(WCHAR);
3725 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3726 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3728 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3729 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3730 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3731 TRACE( "got font path %s\n", debugstr_a(valueA) );
3736 LPSTR next = strchr( ptr, ':' );
3737 if (next) *next++ = 0;
3738 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3739 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3741 strcpy( unixname, home );
3742 strcat( unixname, ptr + 1 );
3743 ReadFontDir( unixname, TRUE );
3744 HeapFree( GetProcessHeap(), 0, unixname );
3747 ReadFontDir( ptr, TRUE );
3750 HeapFree( GetProcessHeap(), 0, valueA );
3752 HeapFree( GetProcessHeap(), 0, valueW );
3758 static BOOL move_to_front(const WCHAR *name)
3760 Family *family, *cursor2;
3761 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3763 if(!strcmpiW(family->FamilyName, name))
3765 list_remove(&family->entry);
3766 list_add_head(&font_list, &family->entry);
3773 static BOOL set_default(const WCHAR **name_list)
3777 if (move_to_front(*name_list)) return TRUE;
3784 static void reorder_font_list(void)
3786 set_default( default_serif_list );
3787 set_default( default_fixed_list );
3788 set_default( default_sans_list );
3791 /*************************************************************
3794 * Initialize FreeType library and create a list of available faces
3796 BOOL WineEngInit(void)
3798 HKEY hkey_font_cache;
3802 /* update locale dependent font info in registry */
3805 if(!init_freetype()) return FALSE;
3807 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3809 ERR("Failed to create font mutex\n");
3812 WaitForSingleObject(font_mutex, INFINITE);
3814 create_font_cache_key(&hkey_font_cache, &disposition);
3816 if(disposition == REG_CREATED_NEW_KEY)
3819 load_font_list_from_cache(hkey_font_cache);
3821 RegCloseKey(hkey_font_cache);
3823 reorder_font_list();
3830 if(disposition == REG_CREATED_NEW_KEY)
3831 update_reg_entries();
3833 init_system_links();
3835 ReleaseMutex(font_mutex);
3840 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3843 TT_HoriHeader *pHori;
3847 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3848 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3850 if(height == 0) height = 16;
3852 /* Calc. height of EM square:
3854 * For +ve lfHeight we have
3855 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3856 * Re-arranging gives:
3857 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3859 * For -ve lfHeight we have
3861 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3862 * with il = winAscent + winDescent - units_per_em]
3867 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3868 ppem = MulDiv(ft_face->units_per_EM, height,
3869 pHori->Ascender - pHori->Descender);
3871 ppem = MulDiv(ft_face->units_per_EM, height,
3872 pOS2->usWinAscent + pOS2->usWinDescent);
3880 static struct font_mapping *map_font_file( const char *name )
3882 struct font_mapping *mapping;
3886 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3887 if (fstat( fd, &st ) == -1) goto error;
3889 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3891 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3893 mapping->refcount++;
3898 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3901 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3904 if (mapping->data == MAP_FAILED)
3906 HeapFree( GetProcessHeap(), 0, mapping );
3909 mapping->refcount = 1;
3910 mapping->dev = st.st_dev;
3911 mapping->ino = st.st_ino;
3912 mapping->size = st.st_size;
3913 list_add_tail( &mappings_list, &mapping->entry );
3921 static void unmap_font_file( struct font_mapping *mapping )
3923 if (!--mapping->refcount)
3925 list_remove( &mapping->entry );
3926 munmap( mapping->data, mapping->size );
3927 HeapFree( GetProcessHeap(), 0, mapping );
3931 static LONG load_VDMX(GdiFont*, LONG);
3933 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3940 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
3944 char *filename = strWtoA( CP_UNIXCP, face->file );
3945 font->mapping = map_font_file( filename );
3946 HeapFree( GetProcessHeap(), 0, filename );
3949 WARN("failed to map %s\n", debugstr_w(face->file));
3952 data_ptr = font->mapping->data;
3953 data_size = font->mapping->size;
3957 data_ptr = face->font_data_ptr;
3958 data_size = face->font_data_size;
3961 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3963 ERR("FT_New_Face rets %d\n", err);
3967 /* set it here, as load_VDMX needs it */
3968 font->ft_face = ft_face;
3970 if(FT_IS_SCALABLE(ft_face)) {
3971 /* load the VDMX table if we have one */
3972 font->ppem = load_VDMX(font, height);
3974 font->ppem = calc_ppem_for_height(ft_face, height);
3975 TRACE("height %d => ppem %d\n", height, font->ppem);
3977 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3978 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3980 font->ppem = height;
3981 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3982 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3988 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3990 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3991 a single face with the requested charset. The idea is to check if
3992 the selected font supports the current ANSI codepage, if it does
3993 return the corresponding charset, else return the first charset */
3996 int acp = GetACP(), i;
4000 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4002 const SYSTEM_LINKS *font_link;
4004 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4005 return csi.ciCharset;
4007 font_link = find_font_link(family_name);
4008 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4009 return csi.ciCharset;
4012 for(i = 0; i < 32; i++) {
4014 if(face->fs.fsCsb[0] & fs0) {
4015 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4017 return csi.ciCharset;
4020 FIXME("TCI failing on %x\n", fs0);
4024 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4025 face->fs.fsCsb[0], debugstr_w(face->file));
4027 return DEFAULT_CHARSET;
4030 static GdiFont *alloc_font(void)
4032 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4034 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4035 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4037 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4038 ret->total_kern_pairs = (DWORD)-1;
4039 ret->kern_pairs = NULL;
4040 list_init(&ret->hfontlist);
4041 list_init(&ret->child_fonts);
4045 static void free_font(GdiFont *font)
4047 struct list *cursor, *cursor2;
4050 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
4052 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
4053 list_remove(cursor);
4055 free_font(child->font);
4056 HeapFree(GetProcessHeap(), 0, child);
4059 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
4061 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
4062 list_remove(&hfontlist->entry);
4063 HeapFree(GetProcessHeap(), 0, hfontlist);
4066 if (font->ft_face) pFT_Done_Face(font->ft_face);
4067 if (font->mapping) unmap_font_file( font->mapping );
4068 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4069 HeapFree(GetProcessHeap(), 0, font->potm);
4070 HeapFree(GetProcessHeap(), 0, font->name);
4071 for (i = 0; i < font->gmsize; i++)
4072 HeapFree(GetProcessHeap(),0,font->gm[i]);
4073 HeapFree(GetProcessHeap(), 0, font->gm);
4074 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4075 HeapFree(GetProcessHeap(), 0, font);
4079 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4081 FT_Face ft_face = font->ft_face;
4085 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4092 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4094 /* make sure value of len is the value freetype says it needs */
4097 FT_ULong needed = 0;
4098 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4099 if( !err && needed < len) len = needed;
4101 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4104 TRACE("Can't find table %c%c%c%c\n",
4105 /* bytes were reversed */
4106 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4107 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4113 /*************************************************************
4116 * load the vdmx entry for the specified height
4119 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4120 ( ( (FT_ULong)_x4 << 24 ) | \
4121 ( (FT_ULong)_x3 << 16 ) | \
4122 ( (FT_ULong)_x2 << 8 ) | \
4125 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4140 static LONG load_VDMX(GdiFont *font, LONG height)
4144 BYTE devXRatio, devYRatio;
4145 USHORT numRecs, numRatios;
4146 DWORD result, offset = -1;
4150 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4152 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4155 /* FIXME: need the real device aspect ratio */
4159 numRecs = GET_BE_WORD(hdr[1]);
4160 numRatios = GET_BE_WORD(hdr[2]);
4162 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4163 for(i = 0; i < numRatios; i++) {
4166 offset = (3 * 2) + (i * sizeof(Ratios));
4167 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4170 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4172 if((ratio.xRatio == 0 &&
4173 ratio.yStartRatio == 0 &&
4174 ratio.yEndRatio == 0) ||
4175 (devXRatio == ratio.xRatio &&
4176 devYRatio >= ratio.yStartRatio &&
4177 devYRatio <= ratio.yEndRatio))
4179 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4180 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4181 offset = GET_BE_WORD(tmp);
4187 FIXME("No suitable ratio found\n");
4191 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4193 BYTE startsz, endsz;
4196 recs = GET_BE_WORD(group.recs);
4197 startsz = group.startsz;
4198 endsz = group.endsz;
4200 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4202 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4203 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4204 if(result == GDI_ERROR) {
4205 FIXME("Failed to retrieve vTable\n");
4210 for(i = 0; i < recs; i++) {
4211 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4212 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4213 ppem = GET_BE_WORD(vTable[i * 3]);
4215 if(yMax + -yMin == height) {
4218 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4221 if(yMax + -yMin > height) {
4224 goto end; /* failed */
4226 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4227 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4228 ppem = GET_BE_WORD(vTable[i * 3]);
4229 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4235 TRACE("ppem not found for height %d\n", height);
4239 HeapFree(GetProcessHeap(), 0, vTable);
4245 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4247 if(font->font_desc.hash != fd->hash) return TRUE;
4248 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4249 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4250 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4251 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4254 static void calc_hash(FONT_DESC *pfd)
4256 DWORD hash = 0, *ptr, two_chars;
4260 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4262 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4264 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4266 pwc = (WCHAR *)&two_chars;
4268 *pwc = toupperW(*pwc);
4270 *pwc = toupperW(*pwc);
4274 hash ^= !pfd->can_use_bitmap;
4279 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4284 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4288 fd.can_use_bitmap = can_use_bitmap;
4291 /* try the in-use list */
4292 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4293 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4294 if(!fontcmp(ret, &fd)) {
4295 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4296 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4297 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4298 if(hflist->hfont == hfont)
4301 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4302 hflist->hfont = hfont;
4303 list_add_head(&ret->hfontlist, &hflist->entry);
4308 /* then the unused list */
4309 font_elem_ptr = list_head(&unused_gdi_font_list);
4310 while(font_elem_ptr) {
4311 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4312 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4313 if(!fontcmp(ret, &fd)) {
4314 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4315 assert(list_empty(&ret->hfontlist));
4316 TRACE("Found %p in unused list\n", ret);
4317 list_remove(&ret->entry);
4318 list_add_head(&gdi_font_list, &ret->entry);
4319 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4320 hflist->hfont = hfont;
4321 list_add_head(&ret->hfontlist, &hflist->entry);
4328 static void add_to_cache(GdiFont *font)
4330 static DWORD cache_num = 1;
4332 font->cache_num = cache_num++;
4333 list_add_head(&gdi_font_list, &font->entry);
4336 /*************************************************************
4337 * create_child_font_list
4339 static BOOL create_child_font_list(GdiFont *font)
4342 SYSTEM_LINKS *font_link;
4343 CHILD_FONT *font_link_entry, *new_child;
4347 psub = get_font_subst(&font_subst_list, font->name, -1);
4348 font_name = psub ? psub->to.name : font->name;
4349 font_link = find_font_link(font_name);
4350 if (font_link != NULL)
4352 TRACE("found entry in system list\n");
4353 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4355 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4356 new_child->face = font_link_entry->face;
4357 new_child->font = NULL;
4358 list_add_tail(&font->child_fonts, &new_child->entry);
4359 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4364 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4365 * Sans Serif. This is how asian windows get default fallbacks for fonts
4367 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4368 font->charset != OEM_CHARSET &&
4369 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4371 font_link = find_font_link(szDefaultFallbackLink);
4372 if (font_link != NULL)
4374 TRACE("found entry in default fallback list\n");
4375 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4377 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4378 new_child->face = font_link_entry->face;
4379 new_child->font = NULL;
4380 list_add_tail(&font->child_fonts, &new_child->entry);
4381 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4390 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4392 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4394 if (pFT_Set_Charmap)
4397 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4399 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4401 for (i = 0; i < ft_face->num_charmaps; i++)
4403 if (ft_face->charmaps[i]->encoding == encoding)
4405 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4406 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4408 switch (ft_face->charmaps[i]->platform_id)
4411 cmap_def = ft_face->charmaps[i];
4413 case 0: /* Apple Unicode */
4414 cmap0 = ft_face->charmaps[i];
4416 case 1: /* Macintosh */
4417 cmap1 = ft_face->charmaps[i];
4420 cmap2 = ft_face->charmaps[i];
4422 case 3: /* Microsoft */
4423 cmap3 = ft_face->charmaps[i];
4428 if (cmap3) /* prefer Microsoft cmap table */
4429 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4431 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4433 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4435 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4437 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4439 return ft_err == FT_Err_Ok;
4442 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4446 /*************************************************************
4449 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4450 LPCWSTR output, const DEVMODEW *devmode )
4452 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4454 if (!physdev) return FALSE;
4455 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4460 /*************************************************************
4463 static BOOL freetype_DeleteDC( PHYSDEV dev )
4465 struct freetype_physdev *physdev = get_freetype_dev( dev );
4466 HeapFree( GetProcessHeap(), 0, physdev );
4470 static FT_Encoding pick_charmap( FT_Face face, int charset )
4472 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4473 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4474 const FT_Encoding *encs = regular_order;
4476 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4480 if (select_charmap( face, *encs )) break;
4486 #define GASP_GRIDFIT 0x01
4487 #define GASP_DOGRAY 0x02
4488 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4490 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4493 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4494 WORD *alloced = NULL, *ptr = buf;
4495 WORD num_recs, version;
4499 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4500 if (size == GDI_ERROR) return FALSE;
4501 if (size < 4 * sizeof(WORD)) return FALSE;
4502 if (size > sizeof(buf))
4504 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4505 if (!ptr) return FALSE;
4508 get_font_data( font, GASP_TAG, 0, ptr, size );
4510 version = GET_BE_WORD( *ptr++ );
4511 num_recs = GET_BE_WORD( *ptr++ );
4513 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4515 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4521 *flags = GET_BE_WORD( *(ptr + 1) );
4522 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4525 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4529 HeapFree( GetProcessHeap(), 0, alloced );
4533 /*************************************************************
4534 * freetype_SelectFont
4536 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4538 struct freetype_physdev *physdev = get_freetype_dev( dev );
4540 Face *face, *best, *best_bitmap;
4541 Family *family, *last_resort_family;
4542 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4543 INT height, width = 0;
4544 unsigned int score = 0, new_score;
4545 signed int diff = 0, newdiff;
4546 BOOL bd, it, can_use_bitmap, want_vertical;
4551 FontSubst *psub = NULL;
4552 DC *dc = get_dc_ptr( dev->hdc );
4553 const SYSTEM_LINKS *font_link;
4555 if (!hfont) /* notification that the font has been changed by another driver */
4557 physdev->font = NULL;
4558 release_dc_ptr( dc );
4562 GetObjectW( hfont, sizeof(lf), &lf );
4563 lf.lfWidth = abs(lf.lfWidth);
4565 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4567 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4568 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4569 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4572 if(dc->GraphicsMode == GM_ADVANCED)
4574 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4575 /* Try to avoid not necessary glyph transformations */
4576 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4578 lf.lfHeight *= fabs(dcmat.eM11);
4579 lf.lfWidth *= fabs(dcmat.eM11);
4580 dcmat.eM11 = dcmat.eM22 = 1.0;
4585 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4586 font scaling abilities. */
4587 dcmat.eM11 = dcmat.eM22 = 1.0;
4588 dcmat.eM21 = dcmat.eM12 = 0;
4589 if (dc->vport2WorldValid)
4591 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4592 lf.lfOrientation = -lf.lfOrientation;
4593 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4594 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4598 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4599 dcmat.eM21, dcmat.eM22);
4602 EnterCriticalSection( &freetype_cs );
4604 /* check the cache first */
4605 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4606 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4610 if(list_empty(&font_list)) /* No fonts installed */
4612 TRACE("No fonts installed\n");
4616 TRACE("not in cache\n");
4619 ret->font_desc.matrix = dcmat;
4620 ret->font_desc.lf = lf;
4621 ret->font_desc.can_use_bitmap = can_use_bitmap;
4622 calc_hash(&ret->font_desc);
4623 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4624 hflist->hfont = hfont;
4625 list_add_head(&ret->hfontlist, &hflist->entry);
4627 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4628 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4629 original value lfCharSet. Note this is a special case for
4630 Symbol and doesn't happen at least for "Wingdings*" */
4632 if(!strcmpiW(lf.lfFaceName, SymbolW))
4633 lf.lfCharSet = SYMBOL_CHARSET;
4635 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4636 switch(lf.lfCharSet) {
4637 case DEFAULT_CHARSET:
4638 csi.fs.fsCsb[0] = 0;
4641 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4642 csi.fs.fsCsb[0] = 0;
4648 if(lf.lfFaceName[0] != '\0') {
4649 CHILD_FONT *font_link_entry;
4650 LPWSTR FaceName = lf.lfFaceName;
4652 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4655 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4656 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4657 if (psub->to.charset != -1)
4658 lf.lfCharSet = psub->to.charset;
4661 /* We want a match on name and charset or just name if
4662 charset was DEFAULT_CHARSET. If the latter then
4663 we fixup the returned charset later in get_nearest_charset
4664 where we'll either use the charset of the current ansi codepage
4665 or if that's unavailable the first charset that the font supports.
4667 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4668 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4669 if (!strcmpiW(family->FamilyName, FaceName) ||
4670 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4672 font_link = find_font_link(family->FamilyName);
4673 face_list = get_face_list_from_family(family);
4674 LIST_FOR_EACH(face_elem_ptr, face_list) {
4675 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4676 if (!(face->scalable || can_use_bitmap))
4678 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4680 if (font_link != NULL &&
4681 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4683 if (!csi.fs.fsCsb[0])
4689 /* Search by full face name. */
4690 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4691 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4692 face_list = get_face_list_from_family(family);
4693 LIST_FOR_EACH(face_elem_ptr, face_list) {
4694 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4695 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4696 (face->scalable || can_use_bitmap))
4698 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4700 font_link = find_font_link(family->FamilyName);
4701 if (font_link != NULL &&
4702 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4709 * Try check the SystemLink list first for a replacement font.
4710 * We may find good replacements there.
4712 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4714 if(!strcmpiW(font_link->font_name, FaceName) ||
4715 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4717 TRACE("found entry in system list\n");
4718 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4720 const SYSTEM_LINKS *links;
4722 face = font_link_entry->face;
4723 if (!(face->scalable || can_use_bitmap))
4725 family = face->family;
4726 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4728 links = find_font_link(family->FamilyName);
4729 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4736 psub = NULL; /* substitution is no more relevant */
4738 /* If requested charset was DEFAULT_CHARSET then try using charset
4739 corresponding to the current ansi codepage */
4740 if (!csi.fs.fsCsb[0])
4743 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4744 FIXME("TCI failed on codepage %d\n", acp);
4745 csi.fs.fsCsb[0] = 0;
4747 lf.lfCharSet = csi.ciCharset;
4750 want_vertical = (lf.lfFaceName[0] == '@');
4752 /* Face families are in the top 4 bits of lfPitchAndFamily,
4753 so mask with 0xF0 before testing */
4755 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4756 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4757 strcpyW(lf.lfFaceName, defFixed);
4758 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4759 strcpyW(lf.lfFaceName, defSerif);
4760 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4761 strcpyW(lf.lfFaceName, defSans);
4763 strcpyW(lf.lfFaceName, defSans);
4764 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4765 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4766 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4767 font_link = find_font_link(family->FamilyName);
4768 face_list = get_face_list_from_family(family);
4769 LIST_FOR_EACH(face_elem_ptr, face_list) {
4770 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4771 if (!(face->scalable || can_use_bitmap))
4773 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4775 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4781 last_resort_family = NULL;
4782 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4783 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4784 font_link = find_font_link(family->FamilyName);
4785 face_list = get_face_list_from_family(family);
4786 LIST_FOR_EACH(face_elem_ptr, face_list) {
4787 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4788 if(face->vertical == want_vertical &&
4789 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4790 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4793 if(can_use_bitmap && !last_resort_family)
4794 last_resort_family = family;
4799 if(last_resort_family) {
4800 family = last_resort_family;
4801 csi.fs.fsCsb[0] = 0;
4805 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4806 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4807 face_list = get_face_list_from_family(family);
4808 LIST_FOR_EACH(face_elem_ptr, face_list) {
4809 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4810 if(face->scalable && face->vertical == want_vertical) {
4811 csi.fs.fsCsb[0] = 0;
4812 WARN("just using first face for now\n");
4815 if(can_use_bitmap && !last_resort_family)
4816 last_resort_family = family;
4819 if(!last_resort_family) {
4820 FIXME("can't find a single appropriate font - bailing\n");
4826 WARN("could only find a bitmap font - this will probably look awful!\n");
4827 family = last_resort_family;
4828 csi.fs.fsCsb[0] = 0;
4831 it = lf.lfItalic ? 1 : 0;
4832 bd = lf.lfWeight > 550 ? 1 : 0;
4834 height = lf.lfHeight;
4836 face = best = best_bitmap = NULL;
4837 font_link = find_font_link(family->FamilyName);
4838 face_list = get_face_list_from_family(family);
4839 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4841 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4842 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4847 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4848 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4849 new_score = (italic ^ it) + (bold ^ bd);
4850 if(!best || new_score <= score)
4852 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4853 italic, bold, it, bd);
4856 if(best->scalable && score == 0) break;
4860 newdiff = height - (signed int)(best->size.height);
4862 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4863 if(!best_bitmap || new_score < score ||
4864 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4866 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4869 if(score == 0 && diff == 0) break;
4876 face = best->scalable ? best : best_bitmap;
4877 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4878 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4881 height = lf.lfHeight;
4885 if(csi.fs.fsCsb[0]) {
4886 ret->charset = lf.lfCharSet;
4887 ret->codepage = csi.ciACP;
4890 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4892 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4893 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
4895 ret->aveWidth = height ? lf.lfWidth : 0;
4897 if(!face->scalable) {
4898 /* Windows uses integer scaling factors for bitmap fonts */
4899 INT scale, scaled_height;
4900 GdiFont *cachedfont;
4902 /* FIXME: rotation of bitmap fonts is ignored */
4903 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4905 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4906 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4907 dcmat.eM11 = dcmat.eM22 = 1.0;
4908 /* As we changed the matrix, we need to search the cache for the font again,
4909 * otherwise we might explode the cache. */
4910 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4911 TRACE("Found cached font after non-scalable matrix rescale!\n");
4916 calc_hash(&ret->font_desc);
4918 if (height != 0) height = diff;
4919 height += face->size.height;
4921 scale = (height + face->size.height - 1) / face->size.height;
4922 scaled_height = scale * face->size.height;
4923 /* Only jump to the next height if the difference <= 25% original height */
4924 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4925 /* The jump between unscaled and doubled is delayed by 1 */
4926 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4927 ret->scale_y = scale;
4929 width = face->size.x_ppem >> 6;
4930 height = face->size.y_ppem >> 6;
4934 TRACE("font scale y: %f\n", ret->scale_y);
4936 ret->ft_face = OpenFontFace(ret, face, width, height);
4945 ret->ntmFlags = face->ntmFlags;
4947 pick_charmap( ret->ft_face, ret->charset );
4949 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4950 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4951 ret->underline = lf.lfUnderline ? 0xff : 0;
4952 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4953 create_child_font_list(ret);
4955 if (face->vertical) /* We need to try to load the GSUB table */
4957 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4958 if (length != GDI_ERROR)
4960 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4961 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4962 TRACE("Loaded GSUB table of %i bytes\n",length);
4965 ret->aa_flags = face->aa_flags;
4967 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4973 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
4975 switch (lf.lfQuality)
4977 case NONANTIALIASED_QUALITY:
4978 case ANTIALIASED_QUALITY:
4979 next->funcs->pSelectFont( dev, hfont, aa_flags );
4981 case CLEARTYPE_QUALITY:
4982 case CLEARTYPE_NATURAL_QUALITY:
4984 if (!*aa_flags) *aa_flags = ret->aa_flags;
4985 next->funcs->pSelectFont( dev, hfont, aa_flags );
4987 /* fixup the antialiasing flags for that font */
4990 case WINE_GGO_HRGB_BITMAP:
4991 case WINE_GGO_HBGR_BITMAP:
4992 case WINE_GGO_VRGB_BITMAP:
4993 case WINE_GGO_VBGR_BITMAP:
4994 if (is_subpixel_rendering_enabled()) break;
4995 *aa_flags = GGO_GRAY4_BITMAP;
4997 case GGO_GRAY2_BITMAP:
4998 case GGO_GRAY4_BITMAP:
4999 case GGO_GRAY8_BITMAP:
5000 case WINE_GGO_GRAY16_BITMAP:
5001 if (is_hinting_enabled())
5004 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5006 TRACE( "font %s %d aa disabled by GASP\n",
5007 debugstr_w(lf.lfFaceName), lf.lfHeight );
5008 *aa_flags = GGO_BITMAP;
5013 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5014 physdev->font = ret;
5016 LeaveCriticalSection( &freetype_cs );
5017 release_dc_ptr( dc );
5018 return ret ? hfont : 0;
5021 static void dump_gdi_font_list(void)
5024 struct list *elem_ptr;
5026 TRACE("---------- gdiFont Cache ----------\n");
5027 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
5028 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
5029 TRACE("gdiFont=%p %s %d\n",
5030 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
5033 TRACE("---------- Unused gdiFont Cache ----------\n");
5034 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
5035 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
5036 TRACE("gdiFont=%p %s %d\n",
5037 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
5041 /*************************************************************
5042 * WineEngDestroyFontInstance
5044 * free the gdiFont associated with this handle
5047 BOOL WineEngDestroyFontInstance(HFONT handle)
5052 struct list *font_elem_ptr, *hfontlist_elem_ptr;
5056 EnterCriticalSection( &freetype_cs );
5058 TRACE("destroying hfont=%p\n", handle);
5060 dump_gdi_font_list();
5062 font_elem_ptr = list_head(&gdi_font_list);
5063 while(font_elem_ptr) {
5064 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
5065 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
5067 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
5068 while(hfontlist_elem_ptr) {
5069 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
5070 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
5071 if(hflist->hfont == handle) {
5072 list_remove(&hflist->entry);
5073 HeapFree(GetProcessHeap(), 0, hflist);
5077 if(list_empty(&gdiFont->hfontlist)) {
5078 TRACE("Moving to Unused list\n");
5079 list_remove(&gdiFont->entry);
5080 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
5085 font_elem_ptr = list_head(&unused_gdi_font_list);
5086 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
5087 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
5088 while(font_elem_ptr) {
5089 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
5090 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
5091 TRACE("freeing %p\n", gdiFont);
5092 list_remove(&gdiFont->entry);
5095 LeaveCriticalSection( &freetype_cs );
5099 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5106 id += IDS_FIRST_SCRIPT;
5107 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5108 if (!rsrc) return 0;
5109 hMem = LoadResource( gdi32_module, rsrc );
5110 if (!hMem) return 0;
5112 p = LockResource( hMem );
5114 while (id--) p += *p + 1;
5116 i = min(LF_FACESIZE - 1, *p);
5117 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5123 /***************************************************
5124 * create_enum_charset_list
5126 * This function creates charset enumeration list because in DEFAULT_CHARSET
5127 * case, the ANSI codepage's charset takes precedence over other charsets.
5128 * This function works as a filter other than DEFAULT_CHARSET case.
5130 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5135 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5136 csi.fs.fsCsb[0] != 0) {
5137 list->element[n].mask = csi.fs.fsCsb[0];
5138 list->element[n].charset = csi.ciCharset;
5139 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5142 else { /* charset is DEFAULT_CHARSET or invalid. */
5146 /* Set the current codepage's charset as the first element. */
5148 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5149 csi.fs.fsCsb[0] != 0) {
5150 list->element[n].mask = csi.fs.fsCsb[0];
5151 list->element[n].charset = csi.ciCharset;
5152 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5153 mask |= csi.fs.fsCsb[0];
5157 /* Fill out left elements. */
5158 for (i = 0; i < 32; i++) {
5160 fs.fsCsb[0] = 1L << i;
5162 if (fs.fsCsb[0] & mask)
5163 continue; /* skip, already added. */
5164 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5165 continue; /* skip, this is an invalid fsCsb bit. */
5167 list->element[n].mask = fs.fsCsb[0];
5168 list->element[n].charset = csi.ciCharset;
5169 load_script_name( i, list->element[n].name );
5170 mask |= fs.fsCsb[0];
5174 /* add catch all mask for remaining bits */
5177 list->element[n].mask = ~mask;
5178 list->element[n].charset = DEFAULT_CHARSET;
5179 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5188 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5189 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5194 if (face->cached_enum_data)
5197 *pelf = face->cached_enum_data->elf;
5198 *pntm = face->cached_enum_data->ntm;
5199 *ptype = face->cached_enum_data->type;
5203 font = alloc_font();
5205 if(face->scalable) {
5209 height = face->size.y_ppem >> 6;
5210 width = face->size.x_ppem >> 6;
5212 font->scale_y = 1.0;
5214 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5220 font->name = strdupW(face->family->FamilyName);
5221 font->ntmFlags = face->ntmFlags;
5223 if (get_outline_text_metrics(font))
5225 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5227 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5228 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5229 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5231 lstrcpynW(pelf->elfLogFont.lfFaceName,
5232 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5234 lstrcpynW(pelf->elfFullName,
5235 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5237 lstrcpynW(pelf->elfStyle,
5238 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5243 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5245 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5246 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5247 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5249 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5251 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5253 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5254 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5257 pntm->ntmTm.ntmFlags = face->ntmFlags;
5258 pntm->ntmFontSig = face->fs;
5260 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5262 pelf->elfLogFont.lfEscapement = 0;
5263 pelf->elfLogFont.lfOrientation = 0;
5264 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5265 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5266 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5267 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5268 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5269 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5270 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5271 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5272 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5273 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5274 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5277 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5278 *ptype |= TRUETYPE_FONTTYPE;
5279 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5280 *ptype |= DEVICE_FONTTYPE;
5281 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5282 *ptype |= RASTER_FONTTYPE;
5284 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5285 if (face->cached_enum_data)
5287 face->cached_enum_data->elf = *pelf;
5288 face->cached_enum_data->ntm = *pntm;
5289 face->cached_enum_data->type = *ptype;
5295 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5297 const struct list *face_list, *face_elem_ptr;
5299 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5301 face_list = get_face_list_from_family(family);
5302 LIST_FOR_EACH(face_elem_ptr, face_list)
5304 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5306 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5312 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5314 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5316 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5319 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5320 FONTENUMPROCW proc, LPARAM lparam)
5323 NEWTEXTMETRICEXW ntm;
5327 GetEnumStructs(face, &elf, &ntm, &type);
5328 for(i = 0; i < list->total; i++) {
5329 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5330 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5331 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5332 i = list->total; /* break out of loop after enumeration */
5336 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5337 /* use the DEFAULT_CHARSET case only if no other charset is present */
5338 if (list->element[i].charset == DEFAULT_CHARSET &&
5339 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5340 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5341 strcpyW(elf.elfScript, list->element[i].name);
5342 if (!elf.elfScript[0])
5343 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5345 /* Font Replacement */
5346 if (family != face->family)
5348 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5350 strcpyW(elf.elfFullName, face->FullName);
5352 strcpyW(elf.elfFullName, family->FamilyName);
5354 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5355 debugstr_w(elf.elfLogFont.lfFaceName),
5356 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5357 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5358 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5359 ntm.ntmTm.ntmFlags);
5360 /* release section before callback (FIXME) */
5361 LeaveCriticalSection( &freetype_cs );
5362 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5363 EnterCriticalSection( &freetype_cs );
5368 /*************************************************************
5369 * freetype_EnumFonts
5371 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5375 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5377 struct enum_charset_list enum_charsets;
5381 lf.lfCharSet = DEFAULT_CHARSET;
5382 lf.lfPitchAndFamily = 0;
5383 lf.lfFaceName[0] = 0;
5387 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5389 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5392 EnterCriticalSection( &freetype_cs );
5393 if(plf->lfFaceName[0]) {
5395 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5398 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5399 debugstr_w(psub->to.name));
5401 strcpyW(lf.lfFaceName, psub->to.name);
5405 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5406 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5407 if(family_matches(family, plf)) {
5408 face_list = get_face_list_from_family(family);
5409 LIST_FOR_EACH(face_elem_ptr, face_list) {
5410 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5411 if (!face_matches(family->FamilyName, face, plf)) continue;
5412 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5417 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5418 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5419 face_list = get_face_list_from_family(family);
5420 face_elem_ptr = list_head(face_list);
5421 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5422 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5425 LeaveCriticalSection( &freetype_cs );
5429 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5431 pt->x.value = vec->x >> 6;
5432 pt->x.fract = (vec->x & 0x3f) << 10;
5433 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5434 pt->y.value = vec->y >> 6;
5435 pt->y.fract = (vec->y & 0x3f) << 10;
5436 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5440 /***************************************************
5441 * According to the MSDN documentation on WideCharToMultiByte,
5442 * certain codepages cannot set the default_used parameter.
5443 * This returns TRUE if the codepage can set that parameter, false else
5444 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5446 static BOOL codepage_sets_default_used(UINT codepage)
5460 * GSUB Table handling functions
5463 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5465 const GSUB_CoverageFormat1* cf1;
5469 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5471 int count = GET_BE_WORD(cf1->GlyphCount);
5473 TRACE("Coverage Format 1, %i glyphs\n",count);
5474 for (i = 0; i < count; i++)
5475 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5479 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5481 const GSUB_CoverageFormat2* cf2;
5484 cf2 = (const GSUB_CoverageFormat2*)cf1;
5486 count = GET_BE_WORD(cf2->RangeCount);
5487 TRACE("Coverage Format 2, %i ranges\n",count);
5488 for (i = 0; i < count; i++)
5490 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5492 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5493 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5495 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5496 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5502 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5507 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5509 const GSUB_ScriptList *script;
5510 const GSUB_Script *deflt = NULL;
5512 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5514 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5515 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5517 const GSUB_Script *scr;
5520 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5521 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5523 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5525 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5531 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5535 const GSUB_LangSys *Lang;
5537 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5539 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5541 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5542 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5544 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5547 offset = GET_BE_WORD(script->DefaultLangSys);
5550 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5556 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5559 const GSUB_FeatureList *feature;
5560 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5562 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5563 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5565 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5566 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5568 const GSUB_Feature *feat;
5569 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5576 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5580 const GSUB_LookupList *lookup;
5581 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5583 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5584 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5586 const GSUB_LookupTable *look;
5587 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5588 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5589 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5590 if (GET_BE_WORD(look->LookupType) != 1)
5591 FIXME("We only handle SubType 1\n");
5596 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5598 const GSUB_SingleSubstFormat1 *ssf1;
5599 offset = GET_BE_WORD(look->SubTable[j]);
5600 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5601 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5603 int offset = GET_BE_WORD(ssf1->Coverage);
5604 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5605 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5607 TRACE(" Glyph 0x%x ->",glyph);
5608 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5609 TRACE(" 0x%x\n",glyph);
5614 const GSUB_SingleSubstFormat2 *ssf2;
5618 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5619 offset = GET_BE_WORD(ssf1->Coverage);
5620 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5621 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5622 TRACE(" Coverage index %i\n",index);
5625 TRACE(" Glyph is 0x%x ->",glyph);
5626 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5627 TRACE("0x%x\n",glyph);
5636 static const char* get_opentype_script(const GdiFont *font)
5639 * I am not sure if this is the correct way to generate our script tag
5642 switch (font->charset)
5644 case ANSI_CHARSET: return "latn";
5645 case BALTIC_CHARSET: return "latn"; /* ?? */
5646 case CHINESEBIG5_CHARSET: return "hani";
5647 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5648 case GB2312_CHARSET: return "hani";
5649 case GREEK_CHARSET: return "grek";
5650 case HANGUL_CHARSET: return "hang";
5651 case RUSSIAN_CHARSET: return "cyrl";
5652 case SHIFTJIS_CHARSET: return "kana";
5653 case TURKISH_CHARSET: return "latn"; /* ?? */
5654 case VIETNAMESE_CHARSET: return "latn";
5655 case JOHAB_CHARSET: return "latn"; /* ?? */
5656 case ARABIC_CHARSET: return "arab";
5657 case HEBREW_CHARSET: return "hebr";
5658 case THAI_CHARSET: return "thai";
5659 default: return "latn";
5663 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5665 const GSUB_Header *header;
5666 const GSUB_Script *script;
5667 const GSUB_LangSys *language;
5668 const GSUB_Feature *feature;
5670 if (!font->GSUB_Table)
5673 header = font->GSUB_Table;
5675 script = GSUB_get_script_table(header, get_opentype_script(font));
5678 TRACE("Script not found\n");
5681 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5684 TRACE("Language not found\n");
5687 feature = GSUB_get_feature(header, language, "vrt2");
5689 feature = GSUB_get_feature(header, language, "vert");
5692 TRACE("vrt2/vert feature not found\n");
5695 return GSUB_apply_feature(header, feature, glyph);
5698 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5702 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5703 WCHAR wc = (WCHAR)glyph;
5705 BOOL *default_used_pointer;
5708 default_used_pointer = NULL;
5709 default_used = FALSE;
5710 if (codepage_sets_default_used(font->codepage))
5711 default_used_pointer = &default_used;
5712 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5714 if (font->codepage == CP_SYMBOL && wc < 0x100)
5715 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5720 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5721 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5725 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5727 if (glyph < 0x100) glyph += 0xf000;
5728 /* there is a number of old pre-Unicode "broken" TTFs, which
5729 do have symbols at U+00XX instead of U+f0XX */
5730 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5731 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5733 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5738 /*************************************************************
5739 * freetype_GetGlyphIndices
5741 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5743 struct freetype_physdev *physdev = get_freetype_dev( dev );
5746 BOOL got_default = FALSE;
5750 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5751 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5754 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5756 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5761 EnterCriticalSection( &freetype_cs );
5763 for(i = 0; i < count; i++)
5765 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5770 if (FT_IS_SFNT(physdev->font->ft_face))
5772 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5773 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5778 get_text_metrics(physdev->font, &textm);
5779 default_char = textm.tmDefaultChar;
5783 pgi[i] = default_char;
5786 LeaveCriticalSection( &freetype_cs );
5790 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5792 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5793 return !memcmp(matrix, &identity, sizeof(FMAT2));
5796 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5798 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5799 return !memcmp(matrix, &identity, sizeof(MAT2));
5802 static inline BYTE get_max_level( UINT format )
5806 case GGO_GRAY2_BITMAP: return 4;
5807 case GGO_GRAY4_BITMAP: return 16;
5808 case GGO_GRAY8_BITMAP: return 64;
5813 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5815 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5816 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5819 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5820 FT_Face ft_face = incoming_font->ft_face;
5821 GdiFont *font = incoming_font;
5822 FT_UInt glyph_index;
5823 DWORD width, height, pitch, needed = 0;
5824 FT_Bitmap ft_bitmap;
5826 INT left, right, top = 0, bottom = 0, adv;
5828 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5829 double widthRatio = 1.0;
5830 FT_Matrix transMat = identityMat;
5831 FT_Matrix transMatUnrotated;
5832 BOOL needsTransform = FALSE;
5833 BOOL tategaki = (font->GSUB_Table != NULL);
5834 UINT original_index;
5836 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5837 buflen, buf, lpmat);
5839 TRACE("font transform %f %f %f %f\n",
5840 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5841 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5843 if(format & GGO_GLYPH_INDEX) {
5844 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5845 original_index = glyph;
5846 format &= ~GGO_GLYPH_INDEX;
5848 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5849 ft_face = font->ft_face;
5850 original_index = glyph_index;
5853 if(format & GGO_UNHINTED) {
5854 load_flags |= FT_LOAD_NO_HINTING;
5855 format &= ~GGO_UNHINTED;
5858 /* tategaki never appears to happen to lower glyph index */
5859 if (glyph_index < TATEGAKI_LOWER_BOUND )
5862 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5863 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5864 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5865 font->gmsize * sizeof(GM*));
5867 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5868 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5870 *lpgm = FONT_GM(font,original_index)->gm;
5871 *abc = FONT_GM(font,original_index)->abc;
5872 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5873 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5874 lpgm->gmCellIncX, lpgm->gmCellIncY);
5875 return 1; /* FIXME */
5879 if (!font->gm[original_index / GM_BLOCK_SIZE])
5880 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5882 /* Scaling factor */
5887 get_text_metrics(font, &tm);
5889 widthRatio = (double)font->aveWidth;
5890 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5893 widthRatio = font->scale_y;
5895 /* Scaling transform */
5896 if (widthRatio != 1.0 || font->scale_y != 1.0)
5899 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5902 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5904 pFT_Matrix_Multiply(&scaleMat, &transMat);
5905 needsTransform = TRUE;
5908 /* Slant transform */
5909 if (font->fake_italic) {
5912 slantMat.xx = (1 << 16);
5913 slantMat.xy = ((1 << 16) >> 2);
5915 slantMat.yy = (1 << 16);
5916 pFT_Matrix_Multiply(&slantMat, &transMat);
5917 needsTransform = TRUE;
5920 /* Rotation transform */
5921 transMatUnrotated = transMat;
5922 if(font->orientation && !tategaki) {
5923 FT_Matrix rotationMat;
5925 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5926 pFT_Vector_Unit(&vecAngle, angle);
5927 rotationMat.xx = vecAngle.x;
5928 rotationMat.xy = -vecAngle.y;
5929 rotationMat.yx = -rotationMat.xy;
5930 rotationMat.yy = rotationMat.xx;
5932 pFT_Matrix_Multiply(&rotationMat, &transMat);
5933 needsTransform = TRUE;
5936 /* World transform */
5937 if (!is_identity_FMAT2(&font->font_desc.matrix))
5940 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5941 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5942 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5943 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5944 pFT_Matrix_Multiply(&worldMat, &transMat);
5945 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5946 needsTransform = TRUE;
5949 /* Extra transformation specified by caller */
5950 if (!is_identity_MAT2(lpmat))
5953 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5954 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5955 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5956 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5957 pFT_Matrix_Multiply(&extraMat, &transMat);
5958 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5959 needsTransform = TRUE;
5962 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
5964 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5967 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5971 if(!needsTransform) {
5972 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5973 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5974 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5976 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5977 bottom = (ft_face->glyph->metrics.horiBearingY -
5978 ft_face->glyph->metrics.height) & -64;
5979 lpgm->gmCellIncX = adv;
5980 lpgm->gmCellIncY = 0;
5987 for(xc = 0; xc < 2; xc++) {
5988 for(yc = 0; yc < 2; yc++) {
5989 vec.x = (ft_face->glyph->metrics.horiBearingX +
5990 xc * ft_face->glyph->metrics.width);
5991 vec.y = ft_face->glyph->metrics.horiBearingY -
5992 yc * ft_face->glyph->metrics.height;
5993 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5994 pFT_Vector_Transform(&vec, &transMat);
5995 if(xc == 0 && yc == 0) {
5996 left = right = vec.x;
5997 top = bottom = vec.y;
5999 if(vec.x < left) left = vec.x;
6000 else if(vec.x > right) right = vec.x;
6001 if(vec.y < bottom) bottom = vec.y;
6002 else if(vec.y > top) top = vec.y;
6007 right = (right + 63) & -64;
6008 bottom = bottom & -64;
6009 top = (top + 63) & -64;
6011 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6012 vec.x = ft_face->glyph->metrics.horiAdvance;
6014 pFT_Vector_Transform(&vec, &transMat);
6015 lpgm->gmCellIncX = (vec.x+63) >> 6;
6016 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6018 vec.x = ft_face->glyph->metrics.horiAdvance;
6020 pFT_Vector_Transform(&vec, &transMatUnrotated);
6021 adv = (vec.x+63) >> 6;
6024 lpgm->gmBlackBoxX = (right - left) >> 6;
6025 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6026 lpgm->gmptGlyphOrigin.x = left >> 6;
6027 lpgm->gmptGlyphOrigin.y = top >> 6;
6028 abc->abcA = left >> 6;
6029 abc->abcB = (right - left) >> 6;
6030 abc->abcC = adv - abc->abcA - abc->abcB;
6032 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6033 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6034 lpgm->gmCellIncX, lpgm->gmCellIncY);
6036 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6037 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6039 FONT_GM(font,original_index)->gm = *lpgm;
6040 FONT_GM(font,original_index)->abc = *abc;
6041 FONT_GM(font,original_index)->init = TRUE;
6044 if(format == GGO_METRICS)
6046 return 1; /* FIXME */
6049 if(ft_face->glyph->format != ft_glyph_format_outline &&
6050 (format == GGO_NATIVE || format == GGO_BEZIER))
6052 TRACE("loaded a bitmap\n");
6058 width = lpgm->gmBlackBoxX;
6059 height = lpgm->gmBlackBoxY;
6060 pitch = ((width + 31) >> 5) << 2;
6061 needed = pitch * height;
6063 if(!buf || !buflen) break;
6065 switch(ft_face->glyph->format) {
6066 case ft_glyph_format_bitmap:
6068 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6069 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
6070 INT h = ft_face->glyph->bitmap.rows;
6072 memcpy(dst, src, w);
6073 src += ft_face->glyph->bitmap.pitch;
6079 case ft_glyph_format_outline:
6080 ft_bitmap.width = width;
6081 ft_bitmap.rows = height;
6082 ft_bitmap.pitch = pitch;
6083 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6084 ft_bitmap.buffer = buf;
6087 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6089 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6091 /* Note: FreeType will only set 'black' bits for us. */
6092 memset(buf, 0, needed);
6093 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6097 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6102 case GGO_GRAY2_BITMAP:
6103 case GGO_GRAY4_BITMAP:
6104 case GGO_GRAY8_BITMAP:
6105 case WINE_GGO_GRAY16_BITMAP:
6107 unsigned int max_level, row, col;
6110 width = lpgm->gmBlackBoxX;
6111 height = lpgm->gmBlackBoxY;
6112 pitch = (width + 3) / 4 * 4;
6113 needed = pitch * height;
6115 if(!buf || !buflen) break;
6117 max_level = get_max_level( format );
6119 switch(ft_face->glyph->format) {
6120 case ft_glyph_format_bitmap:
6122 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6123 INT h = ft_face->glyph->bitmap.rows;
6125 memset( buf, 0, needed );
6127 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6128 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6129 src += ft_face->glyph->bitmap.pitch;
6134 case ft_glyph_format_outline:
6136 ft_bitmap.width = width;
6137 ft_bitmap.rows = height;
6138 ft_bitmap.pitch = pitch;
6139 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6140 ft_bitmap.buffer = buf;
6143 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6145 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6147 memset(ft_bitmap.buffer, 0, buflen);
6149 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6151 if (max_level != 255)
6153 for (row = 0, start = buf; row < height; row++)
6155 for (col = 0, ptr = start; col < width; col++, ptr++)
6156 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6164 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6170 case WINE_GGO_HRGB_BITMAP:
6171 case WINE_GGO_HBGR_BITMAP:
6172 case WINE_GGO_VRGB_BITMAP:
6173 case WINE_GGO_VBGR_BITMAP:
6174 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6176 switch (ft_face->glyph->format)
6178 case FT_GLYPH_FORMAT_BITMAP:
6183 width = lpgm->gmBlackBoxX;
6184 height = lpgm->gmBlackBoxY;
6186 needed = pitch * height;
6188 if (!buf || !buflen) break;
6190 memset(buf, 0, buflen);
6192 src = ft_face->glyph->bitmap.buffer;
6193 src_pitch = ft_face->glyph->bitmap.pitch;
6195 height = min( height, ft_face->glyph->bitmap.rows );
6198 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6200 if ( src[x / 8] & masks[x % 8] )
6201 ((unsigned int *)dst)[x] = ~0u;
6210 case FT_GLYPH_FORMAT_OUTLINE:
6214 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6215 INT x_shift, y_shift;
6217 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6218 FT_Render_Mode render_mode =
6219 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6220 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6222 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6224 if ( render_mode == FT_RENDER_MODE_LCD)
6226 lpgm->gmBlackBoxX += 2;
6227 lpgm->gmptGlyphOrigin.x -= 1;
6231 lpgm->gmBlackBoxY += 2;
6232 lpgm->gmptGlyphOrigin.y += 1;
6236 width = lpgm->gmBlackBoxX;
6237 height = lpgm->gmBlackBoxY;
6239 needed = pitch * height;
6241 if (!buf || !buflen) break;
6243 memset(buf, 0, buflen);
6245 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6247 if ( needsTransform )
6248 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6250 if ( pFT_Library_SetLcdFilter )
6251 pFT_Library_SetLcdFilter( library, lcdfilter );
6252 pFT_Render_Glyph (ft_face->glyph, render_mode);
6254 src = ft_face->glyph->bitmap.buffer;
6255 src_pitch = ft_face->glyph->bitmap.pitch;
6256 src_width = ft_face->glyph->bitmap.width;
6257 src_height = ft_face->glyph->bitmap.rows;
6259 if ( render_mode == FT_RENDER_MODE_LCD)
6267 rgb_interval = src_pitch;
6272 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6273 if ( x_shift < 0 ) x_shift = 0;
6274 if ( x_shift + (src_width / hmul) > width )
6275 x_shift = width - (src_width / hmul);
6277 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6278 if ( y_shift < 0 ) y_shift = 0;
6279 if ( y_shift + (src_height / vmul) > height )
6280 y_shift = height - (src_height / vmul);
6282 dst += x_shift + y_shift * ( pitch / 4 );
6283 while ( src_height )
6285 for ( x = 0; x < src_width / hmul; x++ )
6289 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6290 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6291 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6292 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6296 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6297 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6298 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6299 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6302 src += src_pitch * vmul;
6311 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6323 int contour, point = 0, first_pt;
6324 FT_Outline *outline = &ft_face->glyph->outline;
6325 TTPOLYGONHEADER *pph;
6327 DWORD pph_start, cpfx, type;
6329 if(buflen == 0) buf = NULL;
6331 if (needsTransform && buf) {
6332 pFT_Outline_Transform(outline, &transMat);
6335 for(contour = 0; contour < outline->n_contours; contour++) {
6336 /* Ignore contours containing one point */
6337 if(point == outline->contours[contour]) {
6343 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6346 pph->dwType = TT_POLYGON_TYPE;
6347 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6349 needed += sizeof(*pph);
6351 while(point <= outline->contours[contour]) {
6352 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6353 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6354 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6358 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6361 } while(point <= outline->contours[contour] &&
6362 (outline->tags[point] & FT_Curve_Tag_On) ==
6363 (outline->tags[point-1] & FT_Curve_Tag_On));
6364 /* At the end of a contour Windows adds the start point, but
6366 if(point > outline->contours[contour] &&
6367 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6369 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6371 } else if(point <= outline->contours[contour] &&
6372 outline->tags[point] & FT_Curve_Tag_On) {
6373 /* add closing pt for bezier */
6375 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6383 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6386 pph->cb = needed - pph_start;
6392 /* Convert the quadratic Beziers to cubic Beziers.
6393 The parametric eqn for a cubic Bezier is, from PLRM:
6394 r(t) = at^3 + bt^2 + ct + r0
6395 with the control points:
6400 A quadratic Bezier has the form:
6401 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6403 So equating powers of t leads to:
6404 r1 = 2/3 p1 + 1/3 p0
6405 r2 = 2/3 p1 + 1/3 p2
6406 and of course r0 = p0, r3 = p2
6409 int contour, point = 0, first_pt;
6410 FT_Outline *outline = &ft_face->glyph->outline;
6411 TTPOLYGONHEADER *pph;
6413 DWORD pph_start, cpfx, type;
6414 FT_Vector cubic_control[4];
6415 if(buflen == 0) buf = NULL;
6417 if (needsTransform && buf) {
6418 pFT_Outline_Transform(outline, &transMat);
6421 for(contour = 0; contour < outline->n_contours; contour++) {
6423 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6426 pph->dwType = TT_POLYGON_TYPE;
6427 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6429 needed += sizeof(*pph);
6431 while(point <= outline->contours[contour]) {
6432 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6433 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6434 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6437 if(type == TT_PRIM_LINE) {
6439 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6443 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6446 /* FIXME: Possible optimization in endpoint calculation
6447 if there are two consecutive curves */
6448 cubic_control[0] = outline->points[point-1];
6449 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6450 cubic_control[0].x += outline->points[point].x + 1;
6451 cubic_control[0].y += outline->points[point].y + 1;
6452 cubic_control[0].x >>= 1;
6453 cubic_control[0].y >>= 1;
6455 if(point+1 > outline->contours[contour])
6456 cubic_control[3] = outline->points[first_pt];
6458 cubic_control[3] = outline->points[point+1];
6459 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6460 cubic_control[3].x += outline->points[point].x + 1;
6461 cubic_control[3].y += outline->points[point].y + 1;
6462 cubic_control[3].x >>= 1;
6463 cubic_control[3].y >>= 1;
6466 /* r1 = 1/3 p0 + 2/3 p1
6467 r2 = 1/3 p2 + 2/3 p1 */
6468 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6469 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6470 cubic_control[2] = cubic_control[1];
6471 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6472 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6473 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6474 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6476 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6477 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6478 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6483 } while(point <= outline->contours[contour] &&
6484 (outline->tags[point] & FT_Curve_Tag_On) ==
6485 (outline->tags[point-1] & FT_Curve_Tag_On));
6486 /* At the end of a contour Windows adds the start point,
6487 but only for Beziers and we've already done that.
6489 if(point <= outline->contours[contour] &&
6490 outline->tags[point] & FT_Curve_Tag_On) {
6491 /* This is the closing pt of a bezier, but we've already
6492 added it, so just inc point and carry on */
6499 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6502 pph->cb = needed - pph_start;
6508 FIXME("Unsupported format %d\n", format);
6514 static BOOL get_bitmap_text_metrics(GdiFont *font)
6516 FT_Face ft_face = font->ft_face;
6517 FT_WinFNT_HeaderRec winfnt_header;
6518 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6519 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6520 font->potm->otmSize = size;
6522 #define TM font->potm->otmTextMetrics
6523 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6525 TM.tmHeight = winfnt_header.pixel_height;
6526 TM.tmAscent = winfnt_header.ascent;
6527 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6528 TM.tmInternalLeading = winfnt_header.internal_leading;
6529 TM.tmExternalLeading = winfnt_header.external_leading;
6530 TM.tmAveCharWidth = winfnt_header.avg_width;
6531 TM.tmMaxCharWidth = winfnt_header.max_width;
6532 TM.tmWeight = winfnt_header.weight;
6534 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6535 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6536 TM.tmFirstChar = winfnt_header.first_char;
6537 TM.tmLastChar = winfnt_header.last_char;
6538 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6539 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6540 TM.tmItalic = winfnt_header.italic;
6541 TM.tmUnderlined = font->underline;
6542 TM.tmStruckOut = font->strikeout;
6543 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6544 TM.tmCharSet = winfnt_header.charset;
6548 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6549 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6550 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6551 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6552 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6553 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6554 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6555 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6557 TM.tmDigitizedAspectX = 96; /* FIXME */
6558 TM.tmDigitizedAspectY = 96; /* FIXME */
6560 TM.tmLastChar = 255;
6561 TM.tmDefaultChar = 32;
6562 TM.tmBreakChar = 32;
6563 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6564 TM.tmUnderlined = font->underline;
6565 TM.tmStruckOut = font->strikeout;
6566 /* NB inverted meaning of TMPF_FIXED_PITCH */
6567 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6568 TM.tmCharSet = font->charset;
6576 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6578 double scale_x, scale_y;
6582 scale_x = (double)font->aveWidth;
6583 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6586 scale_x = font->scale_y;
6588 scale_x *= fabs(font->font_desc.matrix.eM11);
6589 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6591 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6592 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6594 SCALE_Y(ptm->tmHeight);
6595 SCALE_Y(ptm->tmAscent);
6596 SCALE_Y(ptm->tmDescent);
6597 SCALE_Y(ptm->tmInternalLeading);
6598 SCALE_Y(ptm->tmExternalLeading);
6599 SCALE_Y(ptm->tmOverhang);
6601 SCALE_X(ptm->tmAveCharWidth);
6602 SCALE_X(ptm->tmMaxCharWidth);
6608 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6610 double scale_x, scale_y;
6614 scale_x = (double)font->aveWidth;
6615 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6618 scale_x = font->scale_y;
6620 scale_x *= fabs(font->font_desc.matrix.eM11);
6621 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6623 scale_font_metrics(font, &potm->otmTextMetrics);
6625 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6626 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6628 SCALE_Y(potm->otmAscent);
6629 SCALE_Y(potm->otmDescent);
6630 SCALE_Y(potm->otmLineGap);
6631 SCALE_Y(potm->otmsCapEmHeight);
6632 SCALE_Y(potm->otmsXHeight);
6633 SCALE_Y(potm->otmrcFontBox.top);
6634 SCALE_Y(potm->otmrcFontBox.bottom);
6635 SCALE_X(potm->otmrcFontBox.left);
6636 SCALE_X(potm->otmrcFontBox.right);
6637 SCALE_Y(potm->otmMacAscent);
6638 SCALE_Y(potm->otmMacDescent);
6639 SCALE_Y(potm->otmMacLineGap);
6640 SCALE_X(potm->otmptSubscriptSize.x);
6641 SCALE_Y(potm->otmptSubscriptSize.y);
6642 SCALE_X(potm->otmptSubscriptOffset.x);
6643 SCALE_Y(potm->otmptSubscriptOffset.y);
6644 SCALE_X(potm->otmptSuperscriptSize.x);
6645 SCALE_Y(potm->otmptSuperscriptSize.y);
6646 SCALE_X(potm->otmptSuperscriptOffset.x);
6647 SCALE_Y(potm->otmptSuperscriptOffset.y);
6648 SCALE_Y(potm->otmsStrikeoutSize);
6649 SCALE_Y(potm->otmsStrikeoutPosition);
6650 SCALE_Y(potm->otmsUnderscoreSize);
6651 SCALE_Y(potm->otmsUnderscorePosition);
6657 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6661 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6663 /* Make sure that the font has sane width/height ratio */
6666 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6668 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6673 *ptm = font->potm->otmTextMetrics;
6674 scale_font_metrics(font, ptm);
6678 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6682 for(i = 0; i < ft_face->num_charmaps; i++)
6684 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6690 static BOOL get_outline_text_metrics(GdiFont *font)
6693 FT_Face ft_face = font->ft_face;
6694 UINT needed, lenfam, lensty, lenface, lenfull;
6696 TT_HoriHeader *pHori;
6697 TT_Postscript *pPost;
6698 FT_Fixed x_scale, y_scale;
6699 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6701 INT ascent, descent;
6703 TRACE("font=%p\n", font);
6705 if(!FT_IS_SCALABLE(ft_face))
6708 needed = sizeof(*font->potm);
6710 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6711 family_nameW = strdupW(font->name);
6713 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6715 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6718 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6719 style_nameW = towstr( CP_ACP, ft_face->style_name );
6721 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6723 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6725 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6728 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6729 face_nameW = strdupW(font->name);
6731 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6732 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6734 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6736 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6739 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6740 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6741 full_nameW = strdupW(fake_nameW);
6743 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6745 /* These names should be read from the TT name table */
6747 /* length of otmpFamilyName */
6750 /* length of otmpFaceName */
6753 /* length of otmpStyleName */
6756 /* length of otmpFullName */
6760 x_scale = ft_face->size->metrics.x_scale;
6761 y_scale = ft_face->size->metrics.y_scale;
6763 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6765 FIXME("Can't find OS/2 table - not TT font?\n");
6769 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6771 FIXME("Can't find HHEA table - not TT font?\n");
6775 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6777 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",
6778 pOS2->usWinAscent, pOS2->usWinDescent,
6779 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6780 pOS2->xAvgCharWidth,
6781 ft_face->ascender, ft_face->descender, ft_face->height,
6782 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6783 ft_face->bbox.yMax, ft_face->bbox.yMin);
6785 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6786 font->potm->otmSize = needed;
6788 #define TM font->potm->otmTextMetrics
6790 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6791 ascent = pHori->Ascender;
6792 descent = -pHori->Descender;
6794 ascent = pOS2->usWinAscent;
6795 descent = pOS2->usWinDescent;
6798 font->ntmCellHeight = ascent + descent;
6799 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6802 TM.tmAscent = font->yMax;
6803 TM.tmDescent = -font->yMin;
6804 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6806 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6807 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6808 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6809 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6812 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6815 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6817 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6818 ((ascent + descent) -
6819 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6821 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6822 if (TM.tmAveCharWidth == 0) {
6823 TM.tmAveCharWidth = 1;
6825 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6826 TM.tmWeight = FW_REGULAR;
6827 if (font->fake_bold)
6828 TM.tmWeight = FW_BOLD;
6831 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6833 if (pOS2->usWeightClass > FW_MEDIUM)
6834 TM.tmWeight = pOS2->usWeightClass;
6836 else if (pOS2->usWeightClass <= FW_MEDIUM)
6837 TM.tmWeight = pOS2->usWeightClass;
6840 TM.tmDigitizedAspectX = 96; /* FIXME */
6841 TM.tmDigitizedAspectY = 96; /* FIXME */
6842 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6843 * symbol range to 0 - f0ff
6846 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6851 case 1257: /* Baltic */
6852 TM.tmLastChar = 0xf8fd;
6855 TM.tmLastChar = 0xf0ff;
6857 TM.tmBreakChar = 0x20;
6858 TM.tmDefaultChar = 0x1f;
6862 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6863 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6865 if(pOS2->usFirstCharIndex <= 1)
6866 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6867 else if (pOS2->usFirstCharIndex > 0xff)
6868 TM.tmBreakChar = 0x20;
6870 TM.tmBreakChar = pOS2->usFirstCharIndex;
6871 TM.tmDefaultChar = TM.tmBreakChar - 1;
6873 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6874 TM.tmUnderlined = font->underline;
6875 TM.tmStruckOut = font->strikeout;
6877 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6878 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6879 (pOS2->version == 0xFFFFU ||
6880 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6881 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6883 TM.tmPitchAndFamily = 0;
6885 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6887 case PAN_FAMILY_SCRIPT:
6888 TM.tmPitchAndFamily |= FF_SCRIPT;
6891 case PAN_FAMILY_DECORATIVE:
6892 TM.tmPitchAndFamily |= FF_DECORATIVE;
6897 case PAN_FAMILY_TEXT_DISPLAY:
6898 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6899 /* which is clearly not what the panose spec says. */
6901 if(TM.tmPitchAndFamily == 0 || /* fixed */
6902 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6903 TM.tmPitchAndFamily = FF_MODERN;
6906 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6911 TM.tmPitchAndFamily |= FF_DONTCARE;
6914 case PAN_SERIF_COVE:
6915 case PAN_SERIF_OBTUSE_COVE:
6916 case PAN_SERIF_SQUARE_COVE:
6917 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6918 case PAN_SERIF_SQUARE:
6919 case PAN_SERIF_THIN:
6920 case PAN_SERIF_BONE:
6921 case PAN_SERIF_EXAGGERATED:
6922 case PAN_SERIF_TRIANGLE:
6923 TM.tmPitchAndFamily |= FF_ROMAN;
6926 case PAN_SERIF_NORMAL_SANS:
6927 case PAN_SERIF_OBTUSE_SANS:
6928 case PAN_SERIF_PERP_SANS:
6929 case PAN_SERIF_FLARED:
6930 case PAN_SERIF_ROUNDED:
6931 TM.tmPitchAndFamily |= FF_SWISS;
6938 if(FT_IS_SCALABLE(ft_face))
6939 TM.tmPitchAndFamily |= TMPF_VECTOR;
6941 if(FT_IS_SFNT(ft_face))
6943 if (font->ntmFlags & NTM_PS_OPENTYPE)
6944 TM.tmPitchAndFamily |= TMPF_DEVICE;
6946 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6949 TM.tmCharSet = font->charset;
6951 font->potm->otmFiller = 0;
6952 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6953 font->potm->otmfsSelection = pOS2->fsSelection;
6954 font->potm->otmfsType = pOS2->fsType;
6955 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6956 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6957 font->potm->otmItalicAngle = 0; /* POST table */
6958 font->potm->otmEMSquare = ft_face->units_per_EM;
6959 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6960 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6961 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6962 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6963 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6964 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6965 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6966 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6967 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6968 font->potm->otmMacAscent = TM.tmAscent;
6969 font->potm->otmMacDescent = -TM.tmDescent;
6970 font->potm->otmMacLineGap = font->potm->otmLineGap;
6971 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6972 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6973 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6974 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6975 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6976 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6977 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6978 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6979 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6980 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6981 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6983 font->potm->otmsUnderscoreSize = 0;
6984 font->potm->otmsUnderscorePosition = 0;
6986 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6987 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6991 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6992 cp = (char*)font->potm + sizeof(*font->potm);
6993 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6994 strcpyW((WCHAR*)cp, family_nameW);
6996 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6997 strcpyW((WCHAR*)cp, style_nameW);
6999 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7000 strcpyW((WCHAR*)cp, face_nameW);
7002 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7003 strcpyW((WCHAR*)cp, full_nameW);
7007 HeapFree(GetProcessHeap(), 0, style_nameW);
7008 HeapFree(GetProcessHeap(), 0, family_nameW);
7009 HeapFree(GetProcessHeap(), 0, face_nameW);
7010 HeapFree(GetProcessHeap(), 0, full_nameW);
7014 /*************************************************************
7015 * freetype_GetGlyphOutline
7017 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7018 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7020 struct freetype_physdev *physdev = get_freetype_dev( dev );
7026 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7027 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7031 EnterCriticalSection( &freetype_cs );
7032 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7033 LeaveCriticalSection( &freetype_cs );
7037 /*************************************************************
7038 * freetype_GetTextMetrics
7040 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7042 struct freetype_physdev *physdev = get_freetype_dev( dev );
7047 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7048 return dev->funcs->pGetTextMetrics( dev, metrics );
7052 EnterCriticalSection( &freetype_cs );
7053 ret = get_text_metrics( physdev->font, metrics );
7054 LeaveCriticalSection( &freetype_cs );
7058 /*************************************************************
7059 * freetype_GetOutlineTextMetrics
7061 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7063 struct freetype_physdev *physdev = get_freetype_dev( dev );
7068 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7069 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7072 TRACE("font=%p\n", physdev->font);
7074 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7077 EnterCriticalSection( &freetype_cs );
7079 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7081 if(cbSize >= physdev->font->potm->otmSize)
7083 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7084 scale_outline_font_metrics(physdev->font, potm);
7086 ret = physdev->font->potm->otmSize;
7088 LeaveCriticalSection( &freetype_cs );
7092 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7094 child->font = alloc_font();
7095 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7096 if(!child->font->ft_face)
7098 free_font(child->font);
7103 child->font->font_desc = font->font_desc;
7104 child->font->ntmFlags = child->face->ntmFlags;
7105 child->font->orientation = font->orientation;
7106 child->font->scale_y = font->scale_y;
7107 child->font->name = strdupW(child->face->family->FamilyName);
7108 child->font->base_font = font;
7109 TRACE("created child font %p for base %p\n", child->font, font);
7113 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7116 CHILD_FONT *child_font;
7119 font = font->base_font;
7121 *linked_font = font;
7123 if((*glyph = get_glyph_index(font, c)))
7125 *glyph = get_GSUB_vert_glyph(font, *glyph);
7129 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7131 if(!child_font->font)
7132 if(!load_child_font(font, child_font))
7135 if(!child_font->font->ft_face)
7137 g = get_glyph_index(child_font->font, c);
7138 g = get_GSUB_vert_glyph(child_font->font, g);
7142 *linked_font = child_font->font;
7149 /*************************************************************
7150 * freetype_GetCharWidth
7152 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7154 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7158 struct freetype_physdev *physdev = get_freetype_dev( dev );
7162 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7163 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7166 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7169 EnterCriticalSection( &freetype_cs );
7170 for(c = firstChar; c <= lastChar; c++) {
7171 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7172 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7174 LeaveCriticalSection( &freetype_cs );
7178 /*************************************************************
7179 * freetype_GetCharABCWidths
7181 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7183 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7186 struct freetype_physdev *physdev = get_freetype_dev( dev );
7190 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7191 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7194 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7197 EnterCriticalSection( &freetype_cs );
7199 for(c = firstChar; c <= lastChar; c++, buffer++)
7200 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7202 LeaveCriticalSection( &freetype_cs );
7206 /*************************************************************
7207 * freetype_GetCharABCWidthsI
7209 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7211 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7214 struct freetype_physdev *physdev = get_freetype_dev( dev );
7218 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7219 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7222 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7226 EnterCriticalSection( &freetype_cs );
7228 for(c = 0; c < count; c++, buffer++)
7229 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7230 &gm, buffer, 0, NULL, &identity );
7232 LeaveCriticalSection( &freetype_cs );
7236 /*************************************************************
7237 * freetype_GetTextExtentExPoint
7239 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7240 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7242 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7248 struct freetype_physdev *physdev = get_freetype_dev( dev );
7252 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7253 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7256 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7259 EnterCriticalSection( &freetype_cs );
7262 get_text_metrics( physdev->font, &tm );
7263 size->cy = tm.tmHeight;
7265 for(idx = 0; idx < count; idx++) {
7266 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7267 size->cx += abc.abcA + abc.abcB + abc.abcC;
7269 if (! pnfit || ext <= max_ext) {
7279 LeaveCriticalSection( &freetype_cs );
7280 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7284 /*************************************************************
7285 * freetype_GetTextExtentExPointI
7287 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7288 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7290 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7296 struct freetype_physdev *physdev = get_freetype_dev( dev );
7300 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7301 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7304 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7307 EnterCriticalSection( &freetype_cs );
7310 get_text_metrics(physdev->font, &tm);
7311 size->cy = tm.tmHeight;
7313 for(idx = 0; idx < count; idx++) {
7314 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7315 &gm, &abc, 0, NULL, &identity );
7316 size->cx += abc.abcA + abc.abcB + abc.abcC;
7318 if (! pnfit || ext <= max_ext) {
7328 LeaveCriticalSection( &freetype_cs );
7329 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7333 /*************************************************************
7334 * freetype_GetFontData
7336 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7338 struct freetype_physdev *physdev = get_freetype_dev( dev );
7342 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7343 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7346 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7347 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7348 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7350 return get_font_data( physdev->font, table, offset, buf, cbData );
7353 /*************************************************************
7354 * freetype_GetTextFace
7356 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7359 struct freetype_physdev *physdev = get_freetype_dev( dev );
7363 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7364 return dev->funcs->pGetTextFace( dev, count, str );
7367 n = strlenW(physdev->font->name) + 1;
7370 lstrcpynW(str, physdev->font->name, count);
7376 /*************************************************************
7377 * freetype_GetTextCharsetInfo
7379 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7381 struct freetype_physdev *physdev = get_freetype_dev( dev );
7385 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7386 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7388 if (fs) *fs = physdev->font->fs;
7389 return physdev->font->charset;
7392 /* Retrieve a list of supported Unicode ranges for a given font.
7393 * Can be called with NULL gs to calculate the buffer size. Returns
7394 * the number of ranges found.
7396 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7398 DWORD num_ranges = 0;
7400 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7403 FT_ULong char_code, char_code_prev;
7406 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7408 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7409 face->num_glyphs, glyph_code, char_code);
7411 if (!glyph_code) return 0;
7415 gs->ranges[0].wcLow = (USHORT)char_code;
7416 gs->ranges[0].cGlyphs = 0;
7417 gs->cGlyphsSupported = 0;
7423 if (char_code < char_code_prev)
7425 ERR("expected increasing char code from FT_Get_Next_Char\n");
7428 if (char_code - char_code_prev > 1)
7433 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7434 gs->ranges[num_ranges - 1].cGlyphs = 1;
7435 gs->cGlyphsSupported++;
7440 gs->ranges[num_ranges - 1].cGlyphs++;
7441 gs->cGlyphsSupported++;
7443 char_code_prev = char_code;
7444 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7448 FIXME("encoding %u not supported\n", face->charmap->encoding);
7453 /*************************************************************
7454 * freetype_GetFontUnicodeRanges
7456 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7458 struct freetype_physdev *physdev = get_freetype_dev( dev );
7459 DWORD size, num_ranges;
7463 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7464 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7467 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7468 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7471 glyphset->cbThis = size;
7472 glyphset->cRanges = num_ranges;
7473 glyphset->flAccel = 0;
7478 /*************************************************************
7479 * freetype_FontIsLinked
7481 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7483 struct freetype_physdev *physdev = get_freetype_dev( dev );
7488 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7489 return dev->funcs->pFontIsLinked( dev );
7493 EnterCriticalSection( &freetype_cs );
7494 ret = !list_empty(&physdev->font->child_fonts);
7495 LeaveCriticalSection( &freetype_cs );
7499 /*************************************************************************
7500 * GetRasterizerCaps (GDI32.@)
7502 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7504 lprs->nSize = sizeof(RASTERIZER_STATUS);
7505 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7506 lprs->nLanguageID = 0;
7510 /*************************************************************
7511 * freetype_GdiRealizationInfo
7513 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7515 struct freetype_physdev *physdev = get_freetype_dev( dev );
7516 realization_info_t *info = ptr;
7520 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7521 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7524 FIXME("(%p, %p): stub!\n", physdev->font, info);
7527 if(FT_IS_SCALABLE(physdev->font->ft_face))
7530 info->cache_num = physdev->font->cache_num;
7531 info->unknown2 = -1;
7535 /*************************************************************************
7536 * Kerning support for TrueType fonts
7538 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7540 struct TT_kern_table
7546 struct TT_kern_subtable
7555 USHORT horizontal : 1;
7557 USHORT cross_stream: 1;
7558 USHORT override : 1;
7559 USHORT reserved1 : 4;
7565 struct TT_format0_kern_subtable
7569 USHORT entrySelector;
7580 static DWORD parse_format0_kern_subtable(GdiFont *font,
7581 const struct TT_format0_kern_subtable *tt_f0_ks,
7582 const USHORT *glyph_to_char,
7583 KERNINGPAIR *kern_pair, DWORD cPairs)
7586 const struct TT_kern_pair *tt_kern_pair;
7588 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7590 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7592 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7593 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7594 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7596 if (!kern_pair || !cPairs)
7599 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7601 nPairs = min(nPairs, cPairs);
7603 for (i = 0; i < nPairs; i++)
7605 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7606 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7607 /* this algorithm appears to better match what Windows does */
7608 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7609 if (kern_pair->iKernAmount < 0)
7611 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7612 kern_pair->iKernAmount -= font->ppem;
7614 else if (kern_pair->iKernAmount > 0)
7616 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7617 kern_pair->iKernAmount += font->ppem;
7619 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7621 TRACE("left %u right %u value %d\n",
7622 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7626 TRACE("copied %u entries\n", nPairs);
7630 /*************************************************************
7631 * freetype_GetKerningPairs
7633 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7637 const struct TT_kern_table *tt_kern_table;
7638 const struct TT_kern_subtable *tt_kern_subtable;
7640 USHORT *glyph_to_char;
7642 struct freetype_physdev *physdev = get_freetype_dev( dev );
7644 if (!(font = physdev->font))
7646 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7647 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7651 EnterCriticalSection( &freetype_cs );
7652 if (font->total_kern_pairs != (DWORD)-1)
7654 if (cPairs && kern_pair)
7656 cPairs = min(cPairs, font->total_kern_pairs);
7657 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7659 else cPairs = font->total_kern_pairs;
7661 LeaveCriticalSection( &freetype_cs );
7665 font->total_kern_pairs = 0;
7667 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7669 if (length == GDI_ERROR)
7671 TRACE("no kerning data in the font\n");
7672 LeaveCriticalSection( &freetype_cs );
7676 buf = HeapAlloc(GetProcessHeap(), 0, length);
7679 WARN("Out of memory\n");
7680 LeaveCriticalSection( &freetype_cs );
7684 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7686 /* build a glyph index to char code map */
7687 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7690 WARN("Out of memory allocating a glyph index to char code map\n");
7691 HeapFree(GetProcessHeap(), 0, buf);
7692 LeaveCriticalSection( &freetype_cs );
7696 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7702 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7704 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7705 font->ft_face->num_glyphs, glyph_code, char_code);
7709 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7711 /* FIXME: This doesn't match what Windows does: it does some fancy
7712 * things with duplicate glyph index to char code mappings, while
7713 * we just avoid overriding existing entries.
7715 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7716 glyph_to_char[glyph_code] = (USHORT)char_code;
7718 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7725 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7726 for (n = 0; n <= 65535; n++)
7727 glyph_to_char[n] = (USHORT)n;
7730 tt_kern_table = buf;
7731 nTables = GET_BE_WORD(tt_kern_table->nTables);
7732 TRACE("version %u, nTables %u\n",
7733 GET_BE_WORD(tt_kern_table->version), nTables);
7735 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7737 for (i = 0; i < nTables; i++)
7739 struct TT_kern_subtable tt_kern_subtable_copy;
7741 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7742 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7743 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7745 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7746 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7747 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7749 /* According to the TrueType specification this is the only format
7750 * that will be properly interpreted by Windows and OS/2
7752 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7754 DWORD new_chunk, old_total = font->total_kern_pairs;
7756 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7757 glyph_to_char, NULL, 0);
7758 font->total_kern_pairs += new_chunk;
7760 if (!font->kern_pairs)
7761 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7762 font->total_kern_pairs * sizeof(*font->kern_pairs));
7764 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7765 font->total_kern_pairs * sizeof(*font->kern_pairs));
7767 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7768 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7771 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7773 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7776 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7777 HeapFree(GetProcessHeap(), 0, buf);
7779 if (cPairs && kern_pair)
7781 cPairs = min(cPairs, font->total_kern_pairs);
7782 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7784 else cPairs = font->total_kern_pairs;
7786 LeaveCriticalSection( &freetype_cs );
7790 static const struct gdi_dc_funcs freetype_funcs =
7792 NULL, /* pAbortDoc */
7793 NULL, /* pAbortPath */
7794 NULL, /* pAlphaBlend */
7795 NULL, /* pAngleArc */
7798 NULL, /* pBeginPath */
7799 NULL, /* pBlendImage */
7801 NULL, /* pCloseFigure */
7802 NULL, /* pCreateCompatibleDC */
7803 freetype_CreateDC, /* pCreateDC */
7804 freetype_DeleteDC, /* pDeleteDC */
7805 NULL, /* pDeleteObject */
7806 NULL, /* pDeviceCapabilities */
7807 NULL, /* pEllipse */
7809 NULL, /* pEndPage */
7810 NULL, /* pEndPath */
7811 freetype_EnumFonts, /* pEnumFonts */
7812 NULL, /* pEnumICMProfiles */
7813 NULL, /* pExcludeClipRect */
7814 NULL, /* pExtDeviceMode */
7815 NULL, /* pExtEscape */
7816 NULL, /* pExtFloodFill */
7817 NULL, /* pExtSelectClipRgn */
7818 NULL, /* pExtTextOut */
7819 NULL, /* pFillPath */
7820 NULL, /* pFillRgn */
7821 NULL, /* pFlattenPath */
7822 freetype_FontIsLinked, /* pFontIsLinked */
7823 NULL, /* pFrameRgn */
7824 NULL, /* pGdiComment */
7825 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7826 NULL, /* pGetBoundsRect */
7827 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7828 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7829 freetype_GetCharWidth, /* pGetCharWidth */
7830 NULL, /* pGetDeviceCaps */
7831 NULL, /* pGetDeviceGammaRamp */
7832 freetype_GetFontData, /* pGetFontData */
7833 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7834 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7835 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7836 NULL, /* pGetICMProfile */
7837 NULL, /* pGetImage */
7838 freetype_GetKerningPairs, /* pGetKerningPairs */
7839 NULL, /* pGetNearestColor */
7840 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7841 NULL, /* pGetPixel */
7842 NULL, /* pGetSystemPaletteEntries */
7843 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7844 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7845 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7846 freetype_GetTextFace, /* pGetTextFace */
7847 freetype_GetTextMetrics, /* pGetTextMetrics */
7848 NULL, /* pGradientFill */
7849 NULL, /* pIntersectClipRect */
7850 NULL, /* pInvertRgn */
7852 NULL, /* pModifyWorldTransform */
7854 NULL, /* pOffsetClipRgn */
7855 NULL, /* pOffsetViewportOrg */
7856 NULL, /* pOffsetWindowOrg */
7857 NULL, /* pPaintRgn */
7860 NULL, /* pPolyBezier */
7861 NULL, /* pPolyBezierTo */
7862 NULL, /* pPolyDraw */
7863 NULL, /* pPolyPolygon */
7864 NULL, /* pPolyPolyline */
7865 NULL, /* pPolygon */
7866 NULL, /* pPolyline */
7867 NULL, /* pPolylineTo */
7868 NULL, /* pPutImage */
7869 NULL, /* pRealizeDefaultPalette */
7870 NULL, /* pRealizePalette */
7871 NULL, /* pRectangle */
7872 NULL, /* pResetDC */
7873 NULL, /* pRestoreDC */
7874 NULL, /* pRoundRect */
7876 NULL, /* pScaleViewportExt */
7877 NULL, /* pScaleWindowExt */
7878 NULL, /* pSelectBitmap */
7879 NULL, /* pSelectBrush */
7880 NULL, /* pSelectClipPath */
7881 freetype_SelectFont, /* pSelectFont */
7882 NULL, /* pSelectPalette */
7883 NULL, /* pSelectPen */
7884 NULL, /* pSetArcDirection */
7885 NULL, /* pSetBkColor */
7886 NULL, /* pSetBkMode */
7887 NULL, /* pSetDCBrushColor */
7888 NULL, /* pSetDCPenColor */
7889 NULL, /* pSetDIBColorTable */
7890 NULL, /* pSetDIBitsToDevice */
7891 NULL, /* pSetDeviceClipping */
7892 NULL, /* pSetDeviceGammaRamp */
7893 NULL, /* pSetLayout */
7894 NULL, /* pSetMapMode */
7895 NULL, /* pSetMapperFlags */
7896 NULL, /* pSetPixel */
7897 NULL, /* pSetPolyFillMode */
7898 NULL, /* pSetROP2 */
7899 NULL, /* pSetRelAbs */
7900 NULL, /* pSetStretchBltMode */
7901 NULL, /* pSetTextAlign */
7902 NULL, /* pSetTextCharacterExtra */
7903 NULL, /* pSetTextColor */
7904 NULL, /* pSetTextJustification */
7905 NULL, /* pSetViewportExt */
7906 NULL, /* pSetViewportOrg */
7907 NULL, /* pSetWindowExt */
7908 NULL, /* pSetWindowOrg */
7909 NULL, /* pSetWorldTransform */
7910 NULL, /* pStartDoc */
7911 NULL, /* pStartPage */
7912 NULL, /* pStretchBlt */
7913 NULL, /* pStretchDIBits */
7914 NULL, /* pStrokeAndFillPath */
7915 NULL, /* pStrokePath */
7916 NULL, /* pUnrealizePalette */
7917 NULL, /* pWidenPath */
7918 NULL, /* wine_get_wgl_driver */
7919 GDI_PRIORITY_FONT_DRV /* priority */
7922 #else /* HAVE_FREETYPE */
7924 /*************************************************************************/
7926 BOOL WineEngInit(void)
7930 BOOL WineEngDestroyFontInstance(HFONT hfont)
7935 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7937 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7941 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7943 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7947 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7949 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7953 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7954 LPCWSTR font_file, LPCWSTR font_path )
7960 /*************************************************************************
7961 * GetRasterizerCaps (GDI32.@)
7963 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7965 lprs->nSize = sizeof(RASTERIZER_STATUS);
7967 lprs->nLanguageID = 0;
7971 #endif /* HAVE_FREETYPE */