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 INT adv; /* These three hold to widths of the unrotated chars */
309 typedef struct tagHFONTLIST {
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 child_font_list = LIST_INIT(child_font_list);
380 static struct list system_links = LIST_INIT(system_links);
382 static struct list font_subst_list = LIST_INIT(font_subst_list);
384 static struct list font_list = LIST_INIT(font_list);
386 struct freetype_physdev
388 struct gdi_physdev dev;
392 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
394 return (struct freetype_physdev *)dev;
397 static const struct gdi_dc_funcs freetype_funcs;
399 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
400 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
401 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
403 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
404 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
405 'W','i','n','d','o','w','s','\\',
406 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
407 'F','o','n','t','s','\0'};
409 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
410 'W','i','n','d','o','w','s',' ','N','T','\\',
411 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
412 'F','o','n','t','s','\0'};
414 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
415 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
416 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
417 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
419 static const WCHAR * const SystemFontValues[] = {
426 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
427 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
429 /* Interesting and well-known (frequently-assumed!) font names */
430 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
431 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 };
432 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
433 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
434 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
435 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
436 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
437 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
439 static const WCHAR arial[] = {'A','r','i','a','l',0};
440 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
441 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};
442 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};
443 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
444 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
445 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
446 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
447 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
448 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
450 static const WCHAR *default_serif_list[] =
454 bitstream_vera_serif,
458 static const WCHAR *default_fixed_list[] =
462 bitstream_vera_sans_mono,
466 static const WCHAR *default_sans_list[] =
479 typedef struct tagFontSubst {
485 /* Registry font cache key and value names */
486 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
487 'F','o','n','t','s',0};
488 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
489 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
490 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
491 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
492 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
493 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
494 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
495 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
496 static const WCHAR face_size_value[] = {'S','i','z','e',0};
497 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
498 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
499 static const WCHAR face_aa_value[] = {'A','n','t','i','a','l','i','a','s','i','n','g',0};
500 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
501 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
502 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
503 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
516 static struct list mappings_list = LIST_INIT( mappings_list );
518 static UINT default_aa_flags;
520 static CRITICAL_SECTION freetype_cs;
521 static CRITICAL_SECTION_DEBUG critsect_debug =
524 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
525 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
527 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
529 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
531 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
532 static BOOL use_default_fallback = FALSE;
534 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
535 static BOOL get_outline_text_metrics(GdiFont *font);
536 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
538 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
539 'W','i','n','d','o','w','s',' ','N','T','\\',
540 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
541 'S','y','s','t','e','m','L','i','n','k',0};
543 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
544 'F','o','n','t','L','i','n','k','\\',
545 'S','y','s','t','e','m','L','i','n','k',0};
547 /****************************************
548 * Notes on .fon files
550 * The fonts System, FixedSys and Terminal are special. There are typically multiple
551 * versions installed for different resolutions and codepages. Windows stores which one to use
552 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
554 * FIXEDFON.FON FixedSys
556 * OEMFONT.FON Terminal
557 * LogPixels Current dpi set by the display control panel applet
558 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
559 * also has a LogPixels value that appears to mirror this)
561 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
562 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
563 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
564 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
565 * so that makes sense.
567 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
568 * to be mapped into the registry on Windows 2000 at least).
571 * ega80woa.fon=ega80850.fon
572 * ega40woa.fon=ega40850.fon
573 * cga80woa.fon=cga80850.fon
574 * cga40woa.fon=cga40850.fon
577 /* These are all structures needed for the GSUB table */
579 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
580 #define TATEGAKI_LOWER_BOUND 0x02F1
596 GSUB_ScriptRecord ScriptRecord[1];
602 } GSUB_LangSysRecord;
607 GSUB_LangSysRecord LangSysRecord[1];
611 WORD LookupOrder; /* Reserved */
612 WORD ReqFeatureIndex;
614 WORD FeatureIndex[1];
620 } GSUB_FeatureRecord;
624 GSUB_FeatureRecord FeatureRecord[1];
628 WORD FeatureParams; /* Reserved */
630 WORD LookupListIndex[1];
649 } GSUB_CoverageFormat1;
654 WORD StartCoverageIndex;
660 GSUB_RangeRecord RangeRecord[1];
661 } GSUB_CoverageFormat2;
664 WORD SubstFormat; /* = 1 */
667 } GSUB_SingleSubstFormat1;
670 WORD SubstFormat; /* = 2 */
674 }GSUB_SingleSubstFormat2;
676 #ifdef HAVE_CARBON_CARBON_H
677 static char *find_cache_dir(void)
681 static char cached_path[MAX_PATH];
682 static const char *wine = "/Wine", *fonts = "/Fonts";
684 if(*cached_path) return cached_path;
686 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
689 WARN("can't create cached data folder\n");
692 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
695 WARN("can't create cached data path\n");
699 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
701 ERR("Could not create full path\n");
705 strcat(cached_path, wine);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
713 strcat(cached_path, fonts);
714 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
716 WARN("Couldn't mkdir %s\n", cached_path);
723 /******************************************************************
726 * Extracts individual TrueType font files from a Mac suitcase font
727 * and saves them into the user's caches directory (see
729 * Returns a NULL terminated array of filenames.
731 * We do this because they are apps that try to read ttf files
732 * themselves and they don't like Mac suitcase files.
734 static char **expand_mac_font(const char *path)
741 const char *filename;
745 unsigned int size, max_size;
748 TRACE("path %s\n", path);
750 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
753 WARN("failed to get ref\n");
757 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
760 TRACE("no data fork, so trying resource fork\n");
761 res_ref = FSOpenResFile(&ref, fsRdPerm);
764 TRACE("unable to open resource fork\n");
771 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
774 CloseResFile(res_ref);
778 out_dir = find_cache_dir();
780 filename = strrchr(path, '/');
781 if(!filename) filename = path;
784 /* output filename has the form out_dir/filename_%04x.ttf */
785 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
792 unsigned short *num_faces_ptr, num_faces, face;
795 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
797 fond = Get1IndResource(fond_res, idx);
799 TRACE("got fond resource %d\n", idx);
802 fam_rec = *(FamRec**)fond;
803 num_faces_ptr = (unsigned short *)(fam_rec + 1);
804 num_faces = GET_BE_WORD(*num_faces_ptr);
806 assoc = (AsscEntry*)(num_faces_ptr + 1);
807 TRACE("num faces %04x\n", num_faces);
808 for(face = 0; face < num_faces; face++, assoc++)
811 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
812 unsigned short size, font_id;
815 size = GET_BE_WORD(assoc->fontSize);
816 font_id = GET_BE_WORD(assoc->fontID);
819 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
823 TRACE("trying to load sfnt id %04x\n", font_id);
824 sfnt = GetResource(sfnt_res, font_id);
827 TRACE("can't get sfnt resource %04x\n", font_id);
831 output = HeapAlloc(GetProcessHeap(), 0, output_len);
836 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
838 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
839 if(fd != -1 || errno == EEXIST)
843 unsigned char *sfnt_data;
846 sfnt_data = *(unsigned char**)sfnt;
847 write(fd, sfnt_data, GetHandleSize(sfnt));
851 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
854 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
856 ret.array[ret.size++] = output;
860 WARN("unable to create %s\n", output);
861 HeapFree(GetProcessHeap(), 0, output);
864 ReleaseResource(sfnt);
867 ReleaseResource(fond);
870 CloseResFile(res_ref);
875 #endif /* HAVE_CARBON_CARBON_H */
877 static inline BOOL is_win9x(void)
879 return GetVersion() & 0x80000000;
882 This function builds an FT_Fixed from a double. It fails if the absolute
883 value of the float number is greater than 32768.
885 static inline FT_Fixed FT_FixedFromFloat(double f)
891 This function builds an FT_Fixed from a FIXED. It simply put f.value
892 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
894 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
896 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
899 static BOOL is_hinting_enabled(void)
901 static int enabled = -1;
905 /* Use the >= 2.2.0 function if available */
906 if (pFT_Get_TrueType_Engine_Type)
908 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
909 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
911 #ifdef FT_DRIVER_HAS_HINTER
914 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
915 FT_Module mod = pFT_Get_Module(library, "truetype");
916 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
919 else enabled = FALSE;
920 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
925 static BOOL is_subpixel_rendering_enabled( void )
927 #ifdef HAVE_FREETYPE_FTLCDFIL_H
928 static int enabled = -1;
931 enabled = (pFT_Library_SetLcdFilter &&
932 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
933 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
942 static const struct list *get_face_list_from_family(const Family *family)
944 if (!list_empty(&family->faces))
945 return &family->faces;
947 return family->replacement;
950 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
956 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
958 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
960 const struct list *face_list;
961 if(face_name && strcmpiW(face_name, family->FamilyName))
963 face_list = get_face_list_from_family(family);
964 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
968 file = strrchrW(face->file, '/');
973 if(!strcmpiW(file, file_name)) return face;
979 static Family *find_family_from_name(const WCHAR *name)
983 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
985 if(!strcmpiW(family->FamilyName, name))
992 static Family *find_family_from_any_name(const WCHAR *name)
996 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
998 if(!strcmpiW(family->FamilyName, name))
1000 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1007 static void DumpSubstList(void)
1011 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1013 if(psub->from.charset != -1 || psub->to.charset != -1)
1014 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1015 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1017 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1018 debugstr_w(psub->to.name));
1023 static LPWSTR strdupW(LPCWSTR p)
1026 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1027 ret = HeapAlloc(GetProcessHeap(), 0, len);
1028 memcpy(ret, p, len);
1032 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1037 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1039 if(!strcmpiW(element->from.name, from_name) &&
1040 (element->from.charset == from_charset ||
1041 element->from.charset == -1))
1048 #define ADD_FONT_SUBST_FORCE 1
1050 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1052 FontSubst *from_exist, *to_exist;
1054 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1056 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1058 list_remove(&from_exist->entry);
1059 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1060 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1061 HeapFree(GetProcessHeap(), 0, from_exist);
1067 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1071 HeapFree(GetProcessHeap(), 0, subst->to.name);
1072 subst->to.name = strdupW(to_exist->to.name);
1075 list_add_tail(subst_list, &subst->entry);
1080 HeapFree(GetProcessHeap(), 0, subst->from.name);
1081 HeapFree(GetProcessHeap(), 0, subst->to.name);
1082 HeapFree(GetProcessHeap(), 0, subst);
1086 static WCHAR *towstr(UINT cp, const char *str)
1091 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1092 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1093 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1097 static char *strWtoA(UINT cp, const WCHAR *str)
1099 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1100 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1101 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1105 static void split_subst_info(NameCs *nc, LPSTR str)
1107 CHAR *p = strrchr(str, ',');
1111 nc->charset = strtol(p+1, NULL, 10);
1114 nc->name = towstr(CP_ACP, str);
1117 static void LoadSubstList(void)
1121 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1125 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1126 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1127 &hkey) == ERROR_SUCCESS) {
1129 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1130 &valuelen, &datalen, NULL, NULL);
1132 valuelen++; /* returned value doesn't include room for '\0' */
1133 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1134 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1138 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1139 &dlen) == ERROR_SUCCESS) {
1140 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1142 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1143 split_subst_info(&psub->from, value);
1144 split_subst_info(&psub->to, data);
1146 /* Win 2000 doesn't allow mapping between different charsets
1147 or mapping of DEFAULT_CHARSET */
1148 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1149 psub->to.charset == DEFAULT_CHARSET) {
1150 HeapFree(GetProcessHeap(), 0, psub->to.name);
1151 HeapFree(GetProcessHeap(), 0, psub->from.name);
1152 HeapFree(GetProcessHeap(), 0, psub);
1154 add_font_subst(&font_subst_list, psub, 0);
1156 /* reset dlen and vlen */
1160 HeapFree(GetProcessHeap(), 0, data);
1161 HeapFree(GetProcessHeap(), 0, value);
1167 /*****************************************************************
1168 * get_name_table_entry
1170 * Supply the platform, encoding, language and name ids in req
1171 * and if the name exists the function will fill in the string
1172 * and string_len members. The string is owned by FreeType so
1173 * don't free it. Returns TRUE if the name is found else FALSE.
1175 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1178 FT_UInt num_names, name_index;
1180 if(FT_IS_SFNT(ft_face))
1182 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1184 for(name_index = 0; name_index < num_names; name_index++)
1186 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1188 if((name.platform_id == req->platform_id) &&
1189 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1190 (name.language_id == req->language_id) &&
1191 (name.name_id == req->name_id))
1193 req->string = name.string;
1194 req->string_len = name.string_len;
1201 req->string_len = 0;
1205 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1210 name.platform_id = TT_PLATFORM_MICROSOFT;
1211 name.language_id = language_id;
1212 name.name_id = name_id;
1214 if(get_name_table_entry(ft_face, &name))
1218 /* String is not nul terminated and string_len is a byte length. */
1219 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1220 for(i = 0; i < name.string_len / 2; i++)
1222 WORD *tmp = (WORD *)&name.string[i * 2];
1223 ret[i] = GET_BE_WORD(*tmp);
1226 TRACE("Got localised name %s\n", debugstr_w(ret));
1232 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1234 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1235 if (f1->scalable) return TRUE;
1236 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1237 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1240 static inline void free_face( Face *face )
1242 HeapFree( GetProcessHeap(), 0, face->file );
1243 HeapFree( GetProcessHeap(), 0, face->StyleName );
1244 HeapFree( GetProcessHeap(), 0, face->FullName );
1245 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1246 HeapFree( GetProcessHeap(), 0, face );
1249 static inline void free_family( Family *family )
1251 Face *face, *cursor2;
1253 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1255 list_remove( &face->entry );
1258 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1259 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1260 HeapFree( GetProcessHeap(), 0, family );
1263 static inline int style_order(const Face *face)
1265 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1273 case NTM_BOLD | NTM_ITALIC:
1276 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1277 debugstr_w(face->family->FamilyName),
1278 debugstr_w(face->StyleName),
1284 static BOOL insert_face_in_family_list( Face *face, Family *family )
1288 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1290 if (faces_equal( face, cursor ))
1292 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1293 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1294 cursor->font_version, face->font_version);
1296 if (face->font_version <= cursor->font_version)
1298 TRACE("Original font %s is newer so skipping %s\n",
1299 debugstr_w(cursor->file), debugstr_w(face->file));
1304 TRACE("Replacing original %s with %s\n",
1305 debugstr_w(cursor->file), debugstr_w(face->file));
1306 list_add_before( &cursor->entry, &face->entry );
1307 face->family = family;
1308 list_remove( &cursor->entry);
1309 free_face( cursor );
1314 TRACE("Adding new %s\n", debugstr_w(face->file));
1316 if (style_order( face ) < style_order( cursor )) break;
1319 list_add_before( &cursor->entry, &face->entry );
1320 face->family = family;
1324 /****************************************************************
1325 * NB This function stores the ptrs to the strings to save copying.
1326 * Don't free them after calling.
1328 static Family *create_family( WCHAR *name, WCHAR *english_name )
1330 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1331 family->FamilyName = name;
1332 family->EnglishName = english_name;
1333 list_init( &family->faces );
1334 family->replacement = &family->faces;
1339 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1341 DWORD type, size = sizeof(DWORD);
1343 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1344 type != REG_DWORD || size != sizeof(DWORD))
1347 return ERROR_BAD_CONFIGURATION;
1349 return ERROR_SUCCESS;
1352 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1354 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1357 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1359 DWORD needed, strike_index = 0;
1362 /* If we have a File Name key then this is a real font, not just the parent
1363 key of a bunch of non-scalable strikes */
1364 needed = buffer_size;
1365 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1368 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1369 face->cached_enum_data = NULL;
1371 face->file = strdupW( buffer );
1372 face->StyleName = strdupW(face_name);
1374 needed = buffer_size;
1375 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1376 face->FullName = strdupW( buffer );
1378 face->FullName = NULL;
1380 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1381 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1382 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1383 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1384 reg_load_dword(hkey_face, face_aa_value, (DWORD*)&face->aa_flags);
1386 needed = sizeof(face->fs);
1387 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1389 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1391 face->scalable = TRUE;
1392 memset(&face->size, 0, sizeof(face->size));
1396 face->scalable = FALSE;
1397 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1398 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1399 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1400 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1401 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1403 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1404 face->size.height, face->size.width, face->size.size >> 6,
1405 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1408 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1409 face->fs.fsCsb[0], face->fs.fsCsb[1],
1410 face->fs.fsUsb[0], face->fs.fsUsb[1],
1411 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1413 insert_face_in_family_list(face, family);
1415 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1418 /* load bitmap strikes */
1420 needed = buffer_size;
1421 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1423 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1425 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1426 RegCloseKey(hkey_strike);
1428 needed = buffer_size;
1432 static void load_font_list_from_cache(HKEY hkey_font_cache)
1434 DWORD size, family_index = 0;
1439 size = sizeof(buffer);
1440 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1442 WCHAR *english_family = NULL;
1443 WCHAR *family_name = strdupW( buffer );
1444 DWORD face_index = 0;
1446 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1447 TRACE("opened family key %s\n", debugstr_w(family_name));
1448 size = sizeof(buffer);
1449 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1450 english_family = strdupW( buffer );
1452 family = create_family(family_name, english_family);
1453 list_add_tail(&font_list, &family->entry);
1457 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1458 subst->from.name = strdupW(english_family);
1459 subst->from.charset = -1;
1460 subst->to.name = strdupW(family_name);
1461 subst->to.charset = -1;
1462 add_font_subst(&font_subst_list, subst, 0);
1465 size = sizeof(buffer);
1466 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1468 WCHAR *face_name = strdupW( buffer );
1471 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1473 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1474 RegCloseKey(hkey_face);
1476 HeapFree( GetProcessHeap(), 0, face_name );
1477 size = sizeof(buffer);
1479 RegCloseKey(hkey_family);
1480 size = sizeof(buffer);
1484 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1487 HKEY hkey_wine_fonts;
1489 /* We don't want to create the fonts key as volatile, so open this first */
1490 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1491 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1492 if(ret != ERROR_SUCCESS)
1494 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1498 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1499 KEY_ALL_ACCESS, NULL, hkey, disposition);
1500 RegCloseKey(hkey_wine_fonts);
1504 static void add_face_to_cache(Face *face)
1506 HKEY hkey_font_cache, hkey_family, hkey_face;
1507 WCHAR *face_key_name;
1509 create_font_cache_key(&hkey_font_cache, NULL);
1511 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1512 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1513 if(face->family->EnglishName)
1514 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1515 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1518 face_key_name = face->StyleName;
1521 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1522 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1523 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1525 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1528 HeapFree(GetProcessHeap(), 0, face_key_name);
1530 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1531 (strlenW(face->file) + 1) * sizeof(WCHAR));
1533 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1534 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1536 reg_save_dword(hkey_face, face_index_value, face->face_index);
1537 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1538 reg_save_dword(hkey_face, face_version_value, face->font_version);
1539 if (face->vertical) reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1540 if (face->aa_flags) reg_save_dword(hkey_face, face_aa_value, face->aa_flags);
1542 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1546 reg_save_dword(hkey_face, face_height_value, face->size.height);
1547 reg_save_dword(hkey_face, face_width_value, face->size.width);
1548 reg_save_dword(hkey_face, face_size_value, face->size.size);
1549 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1550 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1551 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1553 RegCloseKey(hkey_face);
1554 RegCloseKey(hkey_family);
1555 RegCloseKey(hkey_font_cache);
1558 static WCHAR *prepend_at(WCHAR *family)
1565 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1567 strcpyW(str + 1, family);
1568 HeapFree(GetProcessHeap(), 0, family);
1572 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1574 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1575 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1577 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1583 else if (!strcmpiW( *name, *english ))
1585 HeapFree( GetProcessHeap(), 0, *english );
1591 *name = prepend_at( *name );
1592 *english = prepend_at( *english );
1596 static Family *get_family( FT_Face ft_face, BOOL vertical )
1599 WCHAR *name, *english_name;
1601 get_family_names( ft_face, &name, &english_name, vertical );
1603 family = find_family_from_name( name );
1607 family = create_family( name, english_name );
1608 list_add_tail( &font_list, &family->entry );
1612 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1613 subst->from.name = strdupW( english_name );
1614 subst->from.charset = -1;
1615 subst->to.name = strdupW( name );
1616 subst->to.charset = -1;
1617 add_font_subst( &font_subst_list, subst, 0 );
1622 HeapFree( GetProcessHeap(), 0, name );
1623 HeapFree( GetProcessHeap(), 0, english_name );
1629 static inline FT_Fixed get_font_version( FT_Face ft_face )
1631 FT_Fixed version = 0;
1634 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1635 if (header) version = header->Font_Revision;
1640 static inline DWORD get_ntm_flags( FT_Face ft_face )
1643 FT_ULong table_size = 0;
1645 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1646 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1647 if (flags == 0) flags = NTM_REGULAR;
1649 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1650 flags |= NTM_PS_OPENTYPE;
1655 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1657 int internal_leading = 0;
1658 FT_WinFNT_HeaderRec winfnt_header;
1660 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1661 internal_leading = winfnt_header.internal_leading;
1663 return internal_leading;
1666 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1671 FT_WinFNT_HeaderRec winfnt_header;
1674 memset( fs, 0, sizeof(*fs) );
1676 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1679 fs->fsUsb[0] = os2->ulUnicodeRange1;
1680 fs->fsUsb[1] = os2->ulUnicodeRange2;
1681 fs->fsUsb[2] = os2->ulUnicodeRange3;
1682 fs->fsUsb[3] = os2->ulUnicodeRange4;
1684 if (os2->version == 0)
1686 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1687 fs->fsCsb[0] = FS_LATIN1;
1689 fs->fsCsb[0] = FS_SYMBOL;
1693 fs->fsCsb[0] = os2->ulCodePageRange1;
1694 fs->fsCsb[1] = os2->ulCodePageRange2;
1699 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1701 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1702 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1703 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1708 if (fs->fsCsb[0] == 0)
1710 /* let's see if we can find any interesting cmaps */
1711 for (i = 0; i < ft_face->num_charmaps; i++)
1713 switch (ft_face->charmaps[i]->encoding)
1715 case FT_ENCODING_UNICODE:
1716 case FT_ENCODING_APPLE_ROMAN:
1717 fs->fsCsb[0] |= FS_LATIN1;
1719 case FT_ENCODING_MS_SYMBOL:
1720 fs->fsCsb[0] |= FS_SYMBOL;
1729 #define ADDFONT_EXTERNAL_FONT 0x01
1730 #define ADDFONT_FORCE_BITMAP 0x02
1731 #define ADDFONT_ADD_TO_CACHE 0x04
1732 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
1734 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1735 DWORD flags, BOOL vertical, DWORD aa_flags )
1737 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1738 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1740 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1741 if (!face->StyleName)
1742 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1743 if (!face->StyleName)
1745 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1748 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1749 if (!face->FullName)
1750 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1752 face->FullName = prepend_at( face->FullName );
1756 face->file = towstr( CP_UNIXCP, file );
1757 face->font_data_ptr = NULL;
1758 face->font_data_size = 0;
1763 face->font_data_ptr = font_data_ptr;
1764 face->font_data_size = font_data_size;
1767 face->face_index = face_index;
1768 get_fontsig( ft_face, &face->fs );
1769 face->ntmFlags = get_ntm_flags( ft_face );
1770 face->font_version = get_font_version( ft_face );
1772 if (FT_IS_SCALABLE( ft_face ))
1774 memset( &face->size, 0, sizeof(face->size) );
1775 face->scalable = TRUE;
1779 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1780 size->height, size->width, size->size >> 6,
1781 size->x_ppem >> 6, size->y_ppem >> 6);
1782 face->size.height = size->height;
1783 face->size.width = size->width;
1784 face->size.size = size->size;
1785 face->size.x_ppem = size->x_ppem;
1786 face->size.y_ppem = size->y_ppem;
1787 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1788 face->scalable = FALSE;
1791 face->vertical = vertical;
1792 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1793 face->aa_flags = aa_flags;
1794 face->family = NULL;
1795 face->cached_enum_data = NULL;
1797 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1798 face->fs.fsCsb[0], face->fs.fsCsb[1],
1799 face->fs.fsUsb[0], face->fs.fsUsb[1],
1800 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1805 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1806 FT_Long face_index, DWORD flags, BOOL vertical, DWORD aa_flags )
1811 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical, aa_flags );
1812 family = get_family( ft_face, vertical );
1813 if (!insert_face_in_family_list( face, family ))
1819 if (flags & ADDFONT_ADD_TO_CACHE)
1820 add_face_to_cache( face );
1822 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1823 debugstr_w(face->StyleName));
1826 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1827 FT_Long face_index, BOOL allow_bitmap )
1835 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1836 err = pFT_New_Face(library, file, face_index, &ft_face);
1840 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1841 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1846 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1850 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1851 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1853 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1857 if (!FT_IS_SFNT( ft_face ))
1859 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1861 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1867 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1868 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1869 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1871 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1872 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1876 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1877 we don't want to load these. */
1878 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1882 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1884 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1890 if (!ft_face->family_name || !ft_face->style_name)
1892 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1898 pFT_Done_Face( ft_face );
1902 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1905 FT_Long face_index = 0, num_faces;
1907 DWORD aa_flags = HIWORD( flags );
1909 if (!aa_flags) aa_flags = default_aa_flags;
1911 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1912 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1914 #ifdef HAVE_CARBON_CARBON_H
1917 char **mac_list = expand_mac_font(file);
1920 BOOL had_one = FALSE;
1922 for(cursor = mac_list; *cursor; cursor++)
1925 AddFontToList(*cursor, NULL, 0, flags);
1926 HeapFree(GetProcessHeap(), 0, *cursor);
1928 HeapFree(GetProcessHeap(), 0, mac_list);
1933 #endif /* HAVE_CARBON_CARBON_H */
1936 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1937 if (!ft_face) return 0;
1939 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1941 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1942 pFT_Done_Face(ft_face);
1946 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE, aa_flags);
1949 if (FT_HAS_VERTICAL(ft_face))
1951 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE, aa_flags);
1955 num_faces = ft_face->num_faces;
1956 pFT_Done_Face(ft_face);
1957 } while(num_faces > ++face_index);
1961 static void DumpFontList(void)
1965 struct list *family_elem_ptr, *face_elem_ptr;
1967 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1968 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1969 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1970 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1971 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1972 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1974 TRACE(" %d", face->size.height);
1981 /***********************************************************
1982 * The replacement list is a way to map an entire font
1983 * family onto another family. For example adding
1985 * [HKCU\Software\Wine\Fonts\Replacements]
1986 * "Wingdings"="Winedings"
1988 * would enumerate the Winedings font both as Winedings and
1989 * Wingdings. However if a real Wingdings font is present the
1990 * replacement does not take place.
1993 static void LoadReplaceList(void)
1996 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2000 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2001 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2003 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2004 &valuelen, &datalen, NULL, NULL);
2006 valuelen++; /* returned value doesn't include room for '\0' */
2007 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2008 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2012 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2013 &dlen) == ERROR_SUCCESS) {
2014 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2015 /* "NewName"="Oldname" */
2016 if(!find_family_from_any_name(value))
2018 Family * const family = find_family_from_any_name(data);
2021 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2022 if (new_family != NULL)
2024 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2025 new_family->FamilyName = strdupW(value);
2026 new_family->EnglishName = NULL;
2027 list_init(&new_family->faces);
2028 new_family->replacement = &family->faces;
2029 list_add_tail(&font_list, &new_family->entry);
2034 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2039 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2041 /* reset dlen and vlen */
2045 HeapFree(GetProcessHeap(), 0, data);
2046 HeapFree(GetProcessHeap(), 0, value);
2051 static const WCHAR *font_links_list[] =
2053 Lucida_Sans_Unicode,
2054 Microsoft_Sans_Serif,
2058 static const struct font_links_defaults_list
2060 /* Keyed off substitution for "MS Shell Dlg" */
2061 const WCHAR *shelldlg;
2062 /* Maximum of four substitutes, plus terminating NULL pointer */
2063 const WCHAR *substitutes[5];
2064 } font_links_defaults_list[] =
2066 /* Non East-Asian */
2067 { Tahoma, /* FIXME unverified ordering */
2068 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2070 /* Below lists are courtesy of
2071 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2075 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2077 /* Chinese Simplified */
2079 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2083 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2085 /* Chinese Traditional */
2087 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2092 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2094 SYSTEM_LINKS *font_link;
2096 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2098 if(!strcmpiW(font_link->font_name, name))
2105 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2116 SYSTEM_LINKS *font_link;
2118 psub = get_font_subst(&font_subst_list, name, -1);
2119 /* Don't store fonts that are only substitutes for other fonts */
2122 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2126 font_link = find_font_link(name);
2127 if (font_link == NULL)
2129 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2130 font_link->font_name = strdupW(name);
2131 list_init(&font_link->links);
2132 list_add_tail(&system_links, &font_link->entry);
2135 memset(&font_link->fs, 0, sizeof font_link->fs);
2136 for (i = 0; values[i] != NULL; i++)
2138 const struct list *face_list;
2139 CHILD_FONT *child_font;
2142 if (!strcmpiW(name,value))
2144 psub = get_font_subst(&font_subst_list, value, -1);
2146 value = psub->to.name;
2147 family = find_family_from_name(value);
2151 /* Use first extant filename for this Family */
2152 face_list = get_face_list_from_family(family);
2153 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2157 file = strrchrW(face->file, '/');
2166 face = find_face_from_filename(file, value);
2169 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2173 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2174 child_font->face = face;
2175 child_font->font = NULL;
2176 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2177 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2178 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2179 child_font->face->face_index);
2180 list_add_tail(&font_link->links, &child_font->entry);
2182 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2188 /*************************************************************
2191 static BOOL init_system_links(void)
2195 DWORD type, max_val, max_data, val_len, data_len, index;
2196 WCHAR *value, *data;
2197 WCHAR *entry, *next;
2198 SYSTEM_LINKS *font_link, *system_font_link;
2199 CHILD_FONT *child_font;
2200 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2201 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2202 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2207 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2209 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2210 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2211 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2212 val_len = max_val + 1;
2213 data_len = max_data;
2215 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2217 psub = get_font_subst(&font_subst_list, value, -1);
2218 /* Don't store fonts that are only substitutes for other fonts */
2221 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2224 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2225 font_link->font_name = strdupW(value);
2226 memset(&font_link->fs, 0, sizeof font_link->fs);
2227 list_init(&font_link->links);
2228 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2231 CHILD_FONT *child_font;
2233 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2235 next = entry + strlenW(entry) + 1;
2237 face_name = strchrW(entry, ',');
2241 while(isspaceW(*face_name))
2244 psub = get_font_subst(&font_subst_list, face_name, -1);
2246 face_name = psub->to.name;
2248 face = find_face_from_filename(entry, face_name);
2251 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2255 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2256 child_font->face = face;
2257 child_font->font = NULL;
2258 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2259 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2260 TRACE("Adding file %s index %ld\n",
2261 debugstr_w(child_font->face->file), child_font->face->face_index);
2262 list_add_tail(&font_link->links, &child_font->entry);
2264 list_add_tail(&system_links, &font_link->entry);
2266 val_len = max_val + 1;
2267 data_len = max_data;
2270 HeapFree(GetProcessHeap(), 0, value);
2271 HeapFree(GetProcessHeap(), 0, data);
2276 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2278 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2282 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2284 const FontSubst *psub2;
2285 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2287 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2289 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2290 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2292 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2293 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2295 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2297 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2303 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2306 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2307 system_font_link->font_name = strdupW(System);
2308 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2309 list_init(&system_font_link->links);
2311 face = find_face_from_filename(tahoma_ttf, Tahoma);
2314 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2315 child_font->face = face;
2316 child_font->font = NULL;
2317 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2318 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2319 TRACE("Found Tahoma in %s index %ld\n",
2320 debugstr_w(child_font->face->file), child_font->face->face_index);
2321 list_add_tail(&system_font_link->links, &child_font->entry);
2323 font_link = find_font_link(Tahoma);
2324 if (font_link != NULL)
2326 CHILD_FONT *font_link_entry;
2327 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2329 CHILD_FONT *new_child;
2330 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2331 new_child->face = font_link_entry->face;
2332 new_child->font = NULL;
2333 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2334 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2335 list_add_tail(&system_font_link->links, &new_child->entry);
2338 list_add_tail(&system_links, &system_font_link->entry);
2342 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2345 struct dirent *dent;
2346 char path[MAX_PATH];
2348 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2350 dir = opendir(dirname);
2352 WARN("Can't open directory %s\n", debugstr_a(dirname));
2355 while((dent = readdir(dir)) != NULL) {
2356 struct stat statbuf;
2358 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2361 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2363 sprintf(path, "%s/%s", dirname, dent->d_name);
2365 if(stat(path, &statbuf) == -1)
2367 WARN("Can't stat %s\n", debugstr_a(path));
2370 if(S_ISDIR(statbuf.st_mode))
2371 ReadFontDir(path, external_fonts);
2374 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2375 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2376 AddFontToList(path, NULL, 0, addfont_flags);
2383 #ifdef SONAME_LIBFONTCONFIG
2385 static BOOL fontconfig_enabled;
2387 static UINT parse_aa_pattern( FcPattern *pattern )
2393 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2394 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2396 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2400 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2401 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2402 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2403 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2404 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2410 static void init_fontconfig(void)
2412 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2416 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2420 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2421 LOAD_FUNCPTR(FcConfigSubstitute);
2422 LOAD_FUNCPTR(FcFontList);
2423 LOAD_FUNCPTR(FcFontSetDestroy);
2424 LOAD_FUNCPTR(FcInit);
2425 LOAD_FUNCPTR(FcObjectSetAdd);
2426 LOAD_FUNCPTR(FcObjectSetCreate);
2427 LOAD_FUNCPTR(FcObjectSetDestroy);
2428 LOAD_FUNCPTR(FcPatternCreate);
2429 LOAD_FUNCPTR(FcPatternDestroy);
2430 LOAD_FUNCPTR(FcPatternGetBool);
2431 LOAD_FUNCPTR(FcPatternGetInteger);
2432 LOAD_FUNCPTR(FcPatternGetString);
2437 FcPattern *pattern = pFcPatternCreate();
2438 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2439 default_aa_flags = parse_aa_pattern( pattern );
2440 pFcPatternDestroy( pattern );
2441 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2442 fontconfig_enabled = TRUE;
2446 static void load_fontconfig_fonts(void)
2455 if (!fontconfig_enabled) return;
2457 pat = pFcPatternCreate();
2458 os = pFcObjectSetCreate();
2459 pFcObjectSetAdd(os, FC_FILE);
2460 pFcObjectSetAdd(os, FC_SCALABLE);
2461 pFcObjectSetAdd(os, FC_ANTIALIAS);
2462 pFcObjectSetAdd(os, FC_RGBA);
2463 fontset = pFcFontList(NULL, pat, os);
2464 if(!fontset) return;
2465 for(i = 0; i < fontset->nfont; i++) {
2469 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2472 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2474 /* We're just interested in OT/TT fonts for now, so this hack just
2475 picks up the scalable fonts without extensions .pf[ab] to save time
2476 loading every other font */
2478 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2480 TRACE("not scalable\n");
2484 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2485 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2487 len = strlen( file );
2488 if(len < 4) continue;
2489 ext = &file[ len - 3 ];
2490 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2491 AddFontToList(file, NULL, 0,
2492 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2494 pFcFontSetDestroy(fontset);
2495 pFcObjectSetDestroy(os);
2496 pFcPatternDestroy(pat);
2499 #elif defined(HAVE_CARBON_CARBON_H)
2501 static void load_mac_font_callback(const void *value, void *context)
2503 CFStringRef pathStr = value;
2507 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2508 path = HeapAlloc(GetProcessHeap(), 0, len);
2509 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2511 TRACE("font file %s\n", path);
2512 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2514 HeapFree(GetProcessHeap(), 0, path);
2517 static void load_mac_fonts(void)
2519 CFStringRef removeDupesKey;
2520 CFBooleanRef removeDupesValue;
2521 CFDictionaryRef options;
2522 CTFontCollectionRef col;
2524 CFMutableSetRef paths;
2527 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2528 removeDupesValue = kCFBooleanTrue;
2529 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2530 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2531 col = CTFontCollectionCreateFromAvailableFonts(options);
2532 if (options) CFRelease(options);
2535 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2539 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2543 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2547 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2550 WARN("CFSetCreateMutable failed\n");
2555 for (i = 0; i < CFArrayGetCount(descs); i++)
2557 CTFontDescriptorRef desc;
2566 desc = CFArrayGetValueAtIndex(descs, i);
2568 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2569 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2570 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2571 if (!font) continue;
2573 atsFont = CTFontGetPlatformFont(font, NULL);
2580 status = ATSFontGetFileReference(atsFont, &fsref);
2582 if (status != noErr) continue;
2584 url = CFURLCreateFromFSRef(NULL, &fsref);
2587 ext = CFURLCopyPathExtension(url);
2590 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2591 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2600 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2602 if (!path) continue;
2604 CFSetAddValue(paths, path);
2610 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2616 static BOOL load_font_from_data_dir(LPCWSTR file)
2619 const char *data_dir = wine_get_data_dir();
2621 if (!data_dir) data_dir = wine_get_build_dir();
2628 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2630 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2632 strcpy(unix_name, data_dir);
2633 strcat(unix_name, "/fonts/");
2635 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2637 EnterCriticalSection( &freetype_cs );
2638 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2639 LeaveCriticalSection( &freetype_cs );
2640 HeapFree(GetProcessHeap(), 0, unix_name);
2645 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2647 static const WCHAR slashW[] = {'\\','\0'};
2649 WCHAR windowsdir[MAX_PATH];
2652 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2653 strcatW(windowsdir, fontsW);
2654 strcatW(windowsdir, slashW);
2655 strcatW(windowsdir, file);
2656 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2657 EnterCriticalSection( &freetype_cs );
2658 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2659 LeaveCriticalSection( &freetype_cs );
2660 HeapFree(GetProcessHeap(), 0, unixname);
2665 static void load_system_fonts(void)
2668 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2669 const WCHAR * const *value;
2671 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2674 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2675 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2676 strcatW(windowsdir, fontsW);
2677 for(value = SystemFontValues; *value; value++) {
2678 dlen = sizeof(data);
2679 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2683 sprintfW(pathW, fmtW, windowsdir, data);
2684 if((unixname = wine_get_unix_file_name(pathW))) {
2685 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2686 HeapFree(GetProcessHeap(), 0, unixname);
2689 load_font_from_data_dir(data);
2696 /*************************************************************
2698 * This adds registry entries for any externally loaded fonts
2699 * (fonts from fontconfig or FontDirs). It also deletes entries
2700 * of no longer existing fonts.
2703 static void update_reg_entries(void)
2705 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2710 struct list *family_elem_ptr, *face_elem_ptr;
2712 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2714 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2715 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2716 ERR("Can't create Windows font reg key\n");
2720 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2721 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2722 ERR("Can't create Windows font reg key\n");
2726 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2727 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2728 ERR("Can't create external font reg key\n");
2732 /* enumerate the fonts and add external ones to the two keys */
2734 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2735 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2736 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2738 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2739 if(!face->external) continue;
2743 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2744 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2745 strcpyW(valueW, face->FullName);
2749 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2750 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2751 strcpyW(valueW, family->FamilyName);
2754 buffer = strWtoA( CP_UNIXCP, face->file );
2755 path = wine_get_dos_file_name( buffer );
2756 HeapFree( GetProcessHeap(), 0, buffer );
2760 else if ((file = strrchrW(face->file, '/')))
2765 len = strlenW(file) + 1;
2766 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2767 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2768 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2770 HeapFree(GetProcessHeap(), 0, path);
2771 HeapFree(GetProcessHeap(), 0, valueW);
2775 if(external_key) RegCloseKey(external_key);
2776 if(win9x_key) RegCloseKey(win9x_key);
2777 if(winnt_key) RegCloseKey(winnt_key);
2781 static void delete_external_font_keys(void)
2783 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2784 DWORD dlen, vlen, datalen, valuelen, i, type;
2788 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2789 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2790 ERR("Can't create Windows font reg key\n");
2794 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2795 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2796 ERR("Can't create Windows font reg key\n");
2800 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2801 ERR("Can't create external font reg key\n");
2805 /* Delete all external fonts added last time */
2807 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2808 &valuelen, &datalen, NULL, NULL);
2809 valuelen++; /* returned value doesn't include room for '\0' */
2810 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2811 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2813 dlen = datalen * sizeof(WCHAR);
2816 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2817 &dlen) == ERROR_SUCCESS) {
2819 RegDeleteValueW(winnt_key, valueW);
2820 RegDeleteValueW(win9x_key, valueW);
2821 /* reset dlen and vlen */
2825 HeapFree(GetProcessHeap(), 0, data);
2826 HeapFree(GetProcessHeap(), 0, valueW);
2828 /* Delete the old external fonts key */
2829 RegCloseKey(external_key);
2830 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2833 if(win9x_key) RegCloseKey(win9x_key);
2834 if(winnt_key) RegCloseKey(winnt_key);
2837 /*************************************************************
2838 * WineEngAddFontResourceEx
2841 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2847 if (ft_handle) /* do it only if we have freetype up and running */
2852 FIXME("Ignoring flags %x\n", flags);
2854 if((unixname = wine_get_unix_file_name(file)))
2856 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2858 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2859 EnterCriticalSection( &freetype_cs );
2860 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2861 LeaveCriticalSection( &freetype_cs );
2862 HeapFree(GetProcessHeap(), 0, unixname);
2864 if (!ret && !strchrW(file, '\\')) {
2865 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2866 ret = load_font_from_winfonts_dir(file);
2868 /* Try in datadir/fonts (or builddir/fonts),
2869 * needed for Magic the Gathering Online
2871 ret = load_font_from_data_dir(file);
2878 /*************************************************************
2879 * WineEngAddFontMemResourceEx
2882 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2886 if (ft_handle) /* do it only if we have freetype up and running */
2888 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2890 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2891 memcpy(pFontCopy, pbFont, cbFont);
2893 EnterCriticalSection( &freetype_cs );
2894 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2895 LeaveCriticalSection( &freetype_cs );
2899 TRACE("AddFontToList failed\n");
2900 HeapFree(GetProcessHeap(), 0, pFontCopy);
2903 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2904 * For now return something unique but quite random
2906 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2907 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2914 /*************************************************************
2915 * WineEngRemoveFontResourceEx
2918 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2921 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2925 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2931 if (!font_file) return NULL;
2933 file_len = strlenW( font_file );
2935 if (font_path && font_path[0])
2937 int path_len = strlenW( font_path );
2938 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2939 if (!fullname) return NULL;
2940 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2941 fullname[path_len] = '\\';
2942 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2946 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2947 if (!len) return NULL;
2948 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2949 if (!fullname) return NULL;
2950 GetFullPathNameW( font_file, len, fullname, NULL );
2953 unix_name = wine_get_unix_file_name( fullname );
2954 HeapFree( GetProcessHeap(), 0, fullname );
2958 #include <pshpack1.h>
2961 WORD num_of_resources;
2965 CHAR dfCopyright[60];
2971 WORD dfInternalLeading;
2972 WORD dfExternalLeading;
2980 BYTE dfPitchAndFamily;
2991 CHAR szFaceName[LF_FACESIZE];
2994 #include <poppack.h>
2996 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2997 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2999 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3001 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3004 WCHAR *name, *english_name;
3006 NEWTEXTMETRICEXW ntm;
3009 if (!ft_face) return FALSE;
3010 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE, 0 );
3011 get_family_names( ft_face, &name, &english_name, FALSE );
3012 family = create_family( name, english_name );
3013 insert_face_in_family_list( face, family );
3014 pFT_Done_Face( ft_face );
3016 GetEnumStructs( face, &elf, &ntm, &type );
3017 free_family( family );
3019 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3021 memset( fd, 0, sizeof(*fd) );
3023 fd->num_of_resources = 1;
3025 fd->dfVersion = 0x200;
3026 fd->dfSize = sizeof(*fd);
3027 strcpy( fd->dfCopyright, "Wine fontdir" );
3028 fd->dfType = 0x4003; /* 0x0080 set if private */
3029 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3031 fd->dfHorizRes = 72;
3032 fd->dfAscent = ntm.ntmTm.tmAscent;
3033 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3034 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3035 fd->dfItalic = ntm.ntmTm.tmItalic;
3036 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3037 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3038 fd->dfWeight = ntm.ntmTm.tmWeight;
3039 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3041 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3042 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3043 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3044 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3045 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3046 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3047 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3048 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3049 fd->dfWidthBytes = 0;
3051 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3053 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3058 #define NE_FFLAGS_LIBMODULE 0x8000
3059 #define NE_OSFLAGS_WINDOWS 0x02
3061 static const char dos_string[0x40] = "This is a TrueType resource file";
3062 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3064 #include <pshpack2.h>
3085 struct ne_typeinfo fontdir_type;
3086 struct ne_nameinfo fontdir_name;
3087 struct ne_typeinfo scalable_type;
3088 struct ne_nameinfo scalable_name;
3090 BYTE fontdir_res_name[8];
3093 #include <poppack.h>
3095 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3099 DWORD size, written;
3101 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3102 char *font_fileA, *last_part, *ext;
3103 IMAGE_DOS_HEADER dos;
3104 IMAGE_OS2_HEADER ne =
3106 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3108 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3109 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3111 struct rsrc_tab rsrc_tab =
3115 { 0, 0, 0x0c50, 0x2c, 0 },
3117 { 0, 0, 0x0c50, 0x8001, 0 },
3119 { 7,'F','O','N','T','D','I','R'}
3122 memset( &dos, 0, sizeof(dos) );
3123 dos.e_magic = IMAGE_DOS_SIGNATURE;
3124 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3126 /* import name is last part\0, resident name is last part without extension
3127 non-resident name is "FONTRES:" + lfFaceName */
3129 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3130 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3131 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3133 last_part = strrchr( font_fileA, '\\' );
3134 if (last_part) last_part++;
3135 else last_part = font_fileA;
3136 import_name_len = strlen( last_part ) + 1;
3138 ext = strchr( last_part, '.' );
3139 if (ext) res_name_len = ext - last_part;
3140 else res_name_len = import_name_len - 1;
3142 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3144 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3145 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3146 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3147 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3149 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3151 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3152 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3153 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3154 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3156 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3157 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3161 HeapFree( GetProcessHeap(), 0, font_fileA );
3165 memcpy( ptr, &dos, sizeof(dos) );
3166 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3167 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3169 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3170 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3172 ptr = start + dos.e_lfanew + ne.ne_restab;
3173 *ptr++ = res_name_len;
3174 memcpy( ptr, last_part, res_name_len );
3176 ptr = start + dos.e_lfanew + ne.ne_imptab;
3177 *ptr++ = import_name_len;
3178 memcpy( ptr, last_part, import_name_len );
3180 ptr = start + ne.ne_nrestab;
3181 *ptr++ = non_res_name_len;
3182 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3183 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3185 ptr = start + (rsrc_tab.scalable_name.off << 4);
3186 memcpy( ptr, font_fileA, font_file_len );
3188 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3189 memcpy( ptr, fontdir, fontdir->dfSize );
3191 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3192 if (file != INVALID_HANDLE_VALUE)
3194 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3196 CloseHandle( file );
3199 HeapFree( GetProcessHeap(), 0, start );
3200 HeapFree( GetProcessHeap(), 0, font_fileA );
3205 /*************************************************************
3206 * WineEngCreateScalableFontResource
3209 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3210 LPCWSTR font_file, LPCWSTR font_path )
3212 char *unix_name = get_ttf_file_name( font_file, font_path );
3213 struct fontdir fontdir;
3216 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3217 SetLastError( ERROR_INVALID_PARAMETER );
3220 if (hidden) fontdir.dfType |= 0x80;
3221 ret = create_fot( resource, font_file, &fontdir );
3224 HeapFree( GetProcessHeap(), 0, unix_name );
3228 static const struct nls_update_font_list
3230 UINT ansi_cp, oem_cp;
3231 const char *oem, *fixed, *system;
3232 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3233 /* these are for font substitutes */
3234 const char *shelldlg, *tmsrmn;
3235 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3239 const char *from, *to;
3240 } arial_0, courier_new_0, times_new_roman_0;
3241 } nls_update_font_list[] =
3243 /* Latin 1 (United States) */
3244 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3245 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3246 "Tahoma","Times New Roman",
3247 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3250 /* Latin 1 (Multilingual) */
3251 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3252 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3253 "Tahoma","Times New Roman", /* FIXME unverified */
3254 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3257 /* Eastern Europe */
3258 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3259 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3260 "Tahoma","Times New Roman", /* FIXME unverified */
3261 "Fixedsys,238", "System,238",
3262 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3263 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3264 { "Arial CE,0", "Arial,238" },
3265 { "Courier New CE,0", "Courier New,238" },
3266 { "Times New Roman CE,0", "Times New Roman,238" }
3269 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3270 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3271 "Tahoma","Times New Roman", /* FIXME unverified */
3272 "Fixedsys,204", "System,204",
3273 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3274 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3275 { "Arial Cyr,0", "Arial,204" },
3276 { "Courier New Cyr,0", "Courier New,204" },
3277 { "Times New Roman Cyr,0", "Times New Roman,204" }
3280 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3281 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3282 "Tahoma","Times New Roman", /* FIXME unverified */
3283 "Fixedsys,161", "System,161",
3284 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3285 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3286 { "Arial Greek,0", "Arial,161" },
3287 { "Courier New Greek,0", "Courier New,161" },
3288 { "Times New Roman Greek,0", "Times New Roman,161" }
3291 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3292 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3293 "Tahoma","Times New Roman", /* FIXME unverified */
3294 "Fixedsys,162", "System,162",
3295 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3296 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3297 { "Arial Tur,0", "Arial,162" },
3298 { "Courier New Tur,0", "Courier New,162" },
3299 { "Times New Roman Tur,0", "Times New Roman,162" }
3302 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3303 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3304 "Tahoma","Times New Roman", /* FIXME unverified */
3305 "Fixedsys,177", "System,177",
3306 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3307 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3311 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3312 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3313 "Tahoma","Times New Roman", /* FIXME unverified */
3314 "Fixedsys,178", "System,178",
3315 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3316 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3320 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3321 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3322 "Tahoma","Times New Roman", /* FIXME unverified */
3323 "Fixedsys,186", "System,186",
3324 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3325 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3326 { "Arial Baltic,0", "Arial,186" },
3327 { "Courier New Baltic,0", "Courier New,186" },
3328 { "Times New Roman Baltic,0", "Times New Roman,186" }
3331 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3332 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3333 "Tahoma","Times New Roman", /* FIXME unverified */
3334 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3338 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3339 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3340 "Tahoma","Times New Roman", /* FIXME unverified */
3341 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3345 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3346 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3347 "MS UI Gothic","MS Serif",
3348 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3351 /* Chinese Simplified */
3352 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3353 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3354 "SimSun", "NSimSun",
3355 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3359 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3360 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3362 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3365 /* Chinese Traditional */
3366 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3367 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3368 "PMingLiU", "MingLiU",
3369 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3374 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3376 return ( ansi_cp == 932 /* CP932 for Japanese */
3377 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3378 || ansi_cp == 949 /* CP949 for Korean */
3379 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3382 static inline HKEY create_fonts_NT_registry_key(void)
3386 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3387 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3391 static inline HKEY create_fonts_9x_registry_key(void)
3395 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3396 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3400 static inline HKEY create_config_fonts_registry_key(void)
3404 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3405 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3409 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3411 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3413 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3414 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3415 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3416 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3419 static void set_value_key(HKEY hkey, const char *name, const char *value)
3422 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3424 RegDeleteValueA(hkey, name);
3427 static void update_font_info(void)
3429 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3430 char buf[40], cpbuf[40];
3433 UINT i, ansi_cp = 0, oem_cp = 0;
3434 DWORD screen_dpi = 96, font_dpi = 0;
3437 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3438 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3439 &hkey) == ERROR_SUCCESS)
3441 reg_load_dword(hkey, logpixels, &screen_dpi);
3445 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3448 reg_load_dword(hkey, logpixels, &font_dpi);
3450 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3451 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3452 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3453 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3454 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3456 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3457 if (is_dbcs_ansi_cp(ansi_cp))
3458 use_default_fallback = TRUE;
3461 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3463 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3468 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3469 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3471 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3472 ansi_cp, oem_cp, screen_dpi);
3474 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3475 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3478 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3482 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3483 nls_update_font_list[i].oem_cp == oem_cp)
3485 hkey = create_config_fonts_registry_key();
3486 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3487 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3488 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3491 hkey = create_fonts_NT_registry_key();
3492 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3495 hkey = create_fonts_9x_registry_key();
3496 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3499 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3501 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3502 strlen(nls_update_font_list[i].shelldlg)+1);
3503 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3504 strlen(nls_update_font_list[i].tmsrmn)+1);
3506 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3507 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3508 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3509 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3510 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3511 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3512 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3513 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3515 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3516 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3517 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3525 /* Delete the FontSubstitutes from other locales */
3526 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3528 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3529 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3530 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3536 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3539 static BOOL init_freetype(void)
3541 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3544 "Wine cannot find the FreeType font library. To enable Wine to\n"
3545 "use TrueType fonts please install a version of FreeType greater than\n"
3546 "or equal to 2.0.5.\n"
3547 "http://www.freetype.org\n");
3551 #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;}
3553 LOAD_FUNCPTR(FT_Done_Face)
3554 LOAD_FUNCPTR(FT_Get_Char_Index)
3555 LOAD_FUNCPTR(FT_Get_First_Char)
3556 LOAD_FUNCPTR(FT_Get_Module)
3557 LOAD_FUNCPTR(FT_Get_Next_Char)
3558 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3559 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3560 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3561 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3562 LOAD_FUNCPTR(FT_Init_FreeType)
3563 LOAD_FUNCPTR(FT_Library_Version)
3564 LOAD_FUNCPTR(FT_Load_Glyph)
3565 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3566 LOAD_FUNCPTR(FT_Matrix_Multiply)
3567 #ifndef FT_MULFIX_INLINED
3568 LOAD_FUNCPTR(FT_MulFix)
3570 LOAD_FUNCPTR(FT_New_Face)
3571 LOAD_FUNCPTR(FT_New_Memory_Face)
3572 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3573 LOAD_FUNCPTR(FT_Outline_Transform)
3574 LOAD_FUNCPTR(FT_Outline_Translate)
3575 LOAD_FUNCPTR(FT_Render_Glyph)
3576 LOAD_FUNCPTR(FT_Select_Charmap)
3577 LOAD_FUNCPTR(FT_Set_Charmap)
3578 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3579 LOAD_FUNCPTR(FT_Vector_Transform)
3580 LOAD_FUNCPTR(FT_Vector_Unit)
3582 /* Don't warn if these ones are missing */
3583 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3584 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3585 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3588 if(pFT_Init_FreeType(&library) != 0) {
3589 ERR("Can't init FreeType library\n");
3590 wine_dlclose(ft_handle, NULL, 0);
3594 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3596 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3597 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3598 ((FT_Version.minor << 8) & 0x00ff00) |
3599 ((FT_Version.patch ) & 0x0000ff);
3601 font_driver = &freetype_funcs;
3606 "Wine cannot find certain functions that it needs inside the FreeType\n"
3607 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3608 "FreeType to at least version 2.1.4.\n"
3609 "http://www.freetype.org\n");
3610 wine_dlclose(ft_handle, NULL, 0);
3615 static void init_font_list(void)
3617 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3618 static const WCHAR pathW[] = {'P','a','t','h',0};
3620 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3621 WCHAR windowsdir[MAX_PATH];
3623 const char *data_dir;
3625 #ifdef SONAME_LIBFONTCONFIG
3629 delete_external_font_keys();
3631 /* load the system bitmap fonts */
3632 load_system_fonts();
3634 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3635 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3636 strcatW(windowsdir, fontsW);
3637 if((unixname = wine_get_unix_file_name(windowsdir)))
3639 ReadFontDir(unixname, FALSE);
3640 HeapFree(GetProcessHeap(), 0, unixname);
3643 /* load the system truetype fonts */
3644 data_dir = wine_get_data_dir();
3645 if (!data_dir) data_dir = wine_get_build_dir();
3646 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3648 strcpy(unixname, data_dir);
3649 strcat(unixname, "/fonts/");
3650 ReadFontDir(unixname, TRUE);
3651 HeapFree(GetProcessHeap(), 0, unixname);
3654 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3655 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3656 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3658 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3659 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3660 &hkey) == ERROR_SUCCESS)
3662 LPWSTR data, valueW;
3663 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3664 &valuelen, &datalen, NULL, NULL);
3666 valuelen++; /* returned value doesn't include room for '\0' */
3667 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3668 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3671 dlen = datalen * sizeof(WCHAR);
3673 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3674 &dlen) == ERROR_SUCCESS)
3676 if(data[0] && (data[1] == ':'))
3678 if((unixname = wine_get_unix_file_name(data)))
3680 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3681 HeapFree(GetProcessHeap(), 0, unixname);
3684 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3686 WCHAR pathW[MAX_PATH];
3687 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3690 sprintfW(pathW, fmtW, windowsdir, data);
3691 if((unixname = wine_get_unix_file_name(pathW)))
3693 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3694 HeapFree(GetProcessHeap(), 0, unixname);
3697 load_font_from_data_dir(data);
3699 /* reset dlen and vlen */
3704 HeapFree(GetProcessHeap(), 0, data);
3705 HeapFree(GetProcessHeap(), 0, valueW);
3709 #ifdef SONAME_LIBFONTCONFIG
3710 load_fontconfig_fonts();
3711 #elif defined(HAVE_CARBON_CARBON_H)
3715 /* then look in any directories that we've specified in the config file */
3716 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3717 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3723 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3725 len += sizeof(WCHAR);
3726 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3727 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3729 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3730 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3731 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3732 TRACE( "got font path %s\n", debugstr_a(valueA) );
3737 LPSTR next = strchr( ptr, ':' );
3738 if (next) *next++ = 0;
3739 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3740 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3742 strcpy( unixname, home );
3743 strcat( unixname, ptr + 1 );
3744 ReadFontDir( unixname, TRUE );
3745 HeapFree( GetProcessHeap(), 0, unixname );
3748 ReadFontDir( ptr, TRUE );
3751 HeapFree( GetProcessHeap(), 0, valueA );
3753 HeapFree( GetProcessHeap(), 0, valueW );
3759 static BOOL move_to_front(const WCHAR *name)
3761 Family *family, *cursor2;
3762 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3764 if(!strcmpiW(family->FamilyName, name))
3766 list_remove(&family->entry);
3767 list_add_head(&font_list, &family->entry);
3774 static BOOL set_default(const WCHAR **name_list)
3778 if (move_to_front(*name_list)) return TRUE;
3785 static void reorder_font_list(void)
3787 set_default( default_serif_list );
3788 set_default( default_fixed_list );
3789 set_default( default_sans_list );
3792 /*************************************************************
3795 * Initialize FreeType library and create a list of available faces
3797 BOOL WineEngInit(void)
3799 HKEY hkey_font_cache;
3803 /* update locale dependent font info in registry */
3806 if(!init_freetype()) return FALSE;
3808 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3810 ERR("Failed to create font mutex\n");
3813 WaitForSingleObject(font_mutex, INFINITE);
3815 create_font_cache_key(&hkey_font_cache, &disposition);
3817 if(disposition == REG_CREATED_NEW_KEY)
3820 load_font_list_from_cache(hkey_font_cache);
3822 RegCloseKey(hkey_font_cache);
3824 reorder_font_list();
3831 if(disposition == REG_CREATED_NEW_KEY)
3832 update_reg_entries();
3834 init_system_links();
3836 ReleaseMutex(font_mutex);
3841 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3844 TT_HoriHeader *pHori;
3848 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3849 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3851 if(height == 0) height = 16;
3853 /* Calc. height of EM square:
3855 * For +ve lfHeight we have
3856 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3857 * Re-arranging gives:
3858 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3860 * For -ve lfHeight we have
3862 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3863 * with il = winAscent + winDescent - units_per_em]
3868 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3869 ppem = MulDiv(ft_face->units_per_EM, height,
3870 pHori->Ascender - pHori->Descender);
3872 ppem = MulDiv(ft_face->units_per_EM, height,
3873 pOS2->usWinAscent + pOS2->usWinDescent);
3881 static struct font_mapping *map_font_file( const char *name )
3883 struct font_mapping *mapping;
3887 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3888 if (fstat( fd, &st ) == -1) goto error;
3890 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3892 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3894 mapping->refcount++;
3899 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3902 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3905 if (mapping->data == MAP_FAILED)
3907 HeapFree( GetProcessHeap(), 0, mapping );
3910 mapping->refcount = 1;
3911 mapping->dev = st.st_dev;
3912 mapping->ino = st.st_ino;
3913 mapping->size = st.st_size;
3914 list_add_tail( &mappings_list, &mapping->entry );
3922 static void unmap_font_file( struct font_mapping *mapping )
3924 if (!--mapping->refcount)
3926 list_remove( &mapping->entry );
3927 munmap( mapping->data, mapping->size );
3928 HeapFree( GetProcessHeap(), 0, mapping );
3932 static LONG load_VDMX(GdiFont*, LONG);
3934 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3941 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
3945 char *filename = strWtoA( CP_UNIXCP, face->file );
3946 font->mapping = map_font_file( filename );
3947 HeapFree( GetProcessHeap(), 0, filename );
3950 WARN("failed to map %s\n", debugstr_w(face->file));
3953 data_ptr = font->mapping->data;
3954 data_size = font->mapping->size;
3958 data_ptr = face->font_data_ptr;
3959 data_size = face->font_data_size;
3962 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3964 ERR("FT_New_Face rets %d\n", err);
3968 /* set it here, as load_VDMX needs it */
3969 font->ft_face = ft_face;
3971 if(FT_IS_SCALABLE(ft_face)) {
3972 /* load the VDMX table if we have one */
3973 font->ppem = load_VDMX(font, height);
3975 font->ppem = calc_ppem_for_height(ft_face, height);
3976 TRACE("height %d => ppem %d\n", height, font->ppem);
3978 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3979 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3981 font->ppem = height;
3982 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3983 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3989 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3991 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3992 a single face with the requested charset. The idea is to check if
3993 the selected font supports the current ANSI codepage, if it does
3994 return the corresponding charset, else return the first charset */
3997 int acp = GetACP(), i;
4001 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4003 const SYSTEM_LINKS *font_link;
4005 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4006 return csi.ciCharset;
4008 font_link = find_font_link(family_name);
4009 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4010 return csi.ciCharset;
4013 for(i = 0; i < 32; i++) {
4015 if(face->fs.fsCsb[0] & fs0) {
4016 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4018 return csi.ciCharset;
4021 FIXME("TCI failing on %x\n", fs0);
4025 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4026 face->fs.fsCsb[0], debugstr_w(face->file));
4028 return DEFAULT_CHARSET;
4031 static GdiFont *alloc_font(void)
4033 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4035 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4036 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4038 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4039 ret->total_kern_pairs = (DWORD)-1;
4040 ret->kern_pairs = NULL;
4041 list_init(&ret->hfontlist);
4042 list_init(&ret->child_fonts);
4046 static void free_font(GdiFont *font)
4048 struct list *cursor, *cursor2;
4051 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
4053 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
4054 list_remove(cursor);
4056 free_font(child->font);
4057 HeapFree(GetProcessHeap(), 0, child);
4060 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
4062 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
4063 DeleteObject(hfontlist->hfont);
4064 list_remove(&hfontlist->entry);
4065 HeapFree(GetProcessHeap(), 0, hfontlist);
4068 if (font->ft_face) pFT_Done_Face(font->ft_face);
4069 if (font->mapping) unmap_font_file( font->mapping );
4070 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4071 HeapFree(GetProcessHeap(), 0, font->potm);
4072 HeapFree(GetProcessHeap(), 0, font->name);
4073 for (i = 0; i < font->gmsize; i++)
4074 HeapFree(GetProcessHeap(),0,font->gm[i]);
4075 HeapFree(GetProcessHeap(), 0, font->gm);
4076 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4077 HeapFree(GetProcessHeap(), 0, font);
4081 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4083 FT_Face ft_face = font->ft_face;
4087 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4094 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4096 /* make sure value of len is the value freetype says it needs */
4099 FT_ULong needed = 0;
4100 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4101 if( !err && needed < len) len = needed;
4103 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4106 TRACE("Can't find table %c%c%c%c\n",
4107 /* bytes were reversed */
4108 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4109 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4115 /*************************************************************
4118 * load the vdmx entry for the specified height
4121 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4122 ( ( (FT_ULong)_x4 << 24 ) | \
4123 ( (FT_ULong)_x3 << 16 ) | \
4124 ( (FT_ULong)_x2 << 8 ) | \
4127 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4142 static LONG load_VDMX(GdiFont *font, LONG height)
4146 BYTE devXRatio, devYRatio;
4147 USHORT numRecs, numRatios;
4148 DWORD result, offset = -1;
4152 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4154 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4157 /* FIXME: need the real device aspect ratio */
4161 numRecs = GET_BE_WORD(hdr[1]);
4162 numRatios = GET_BE_WORD(hdr[2]);
4164 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4165 for(i = 0; i < numRatios; i++) {
4168 offset = (3 * 2) + (i * sizeof(Ratios));
4169 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4172 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4174 if((ratio.xRatio == 0 &&
4175 ratio.yStartRatio == 0 &&
4176 ratio.yEndRatio == 0) ||
4177 (devXRatio == ratio.xRatio &&
4178 devYRatio >= ratio.yStartRatio &&
4179 devYRatio <= ratio.yEndRatio))
4181 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4182 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4183 offset = GET_BE_WORD(tmp);
4189 FIXME("No suitable ratio found\n");
4193 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4195 BYTE startsz, endsz;
4198 recs = GET_BE_WORD(group.recs);
4199 startsz = group.startsz;
4200 endsz = group.endsz;
4202 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4204 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4205 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4206 if(result == GDI_ERROR) {
4207 FIXME("Failed to retrieve vTable\n");
4212 for(i = 0; i < recs; i++) {
4213 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4214 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4215 ppem = GET_BE_WORD(vTable[i * 3]);
4217 if(yMax + -yMin == height) {
4220 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4223 if(yMax + -yMin > height) {
4226 goto end; /* failed */
4228 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4229 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4230 ppem = GET_BE_WORD(vTable[i * 3]);
4231 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4237 TRACE("ppem not found for height %d\n", height);
4241 HeapFree(GetProcessHeap(), 0, vTable);
4247 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4249 if(font->font_desc.hash != fd->hash) return TRUE;
4250 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4251 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4252 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4253 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4256 static void calc_hash(FONT_DESC *pfd)
4258 DWORD hash = 0, *ptr, two_chars;
4262 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4264 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4266 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4268 pwc = (WCHAR *)&two_chars;
4270 *pwc = toupperW(*pwc);
4272 *pwc = toupperW(*pwc);
4276 hash ^= !pfd->can_use_bitmap;
4281 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4286 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4290 fd.can_use_bitmap = can_use_bitmap;
4293 /* try the child list */
4294 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4295 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4296 if(!fontcmp(ret, &fd)) {
4297 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4298 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4299 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4300 if(hflist->hfont == hfont)
4306 /* try the in-use list */
4307 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4308 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4309 if(!fontcmp(ret, &fd)) {
4310 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4311 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4312 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4313 if(hflist->hfont == hfont)
4316 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4317 hflist->hfont = hfont;
4318 list_add_head(&ret->hfontlist, &hflist->entry);
4323 /* then the unused list */
4324 font_elem_ptr = list_head(&unused_gdi_font_list);
4325 while(font_elem_ptr) {
4326 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4327 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4328 if(!fontcmp(ret, &fd)) {
4329 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4330 assert(list_empty(&ret->hfontlist));
4331 TRACE("Found %p in unused list\n", ret);
4332 list_remove(&ret->entry);
4333 list_add_head(&gdi_font_list, &ret->entry);
4334 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4335 hflist->hfont = hfont;
4336 list_add_head(&ret->hfontlist, &hflist->entry);
4343 static void add_to_cache(GdiFont *font)
4345 static DWORD cache_num = 1;
4347 font->cache_num = cache_num++;
4348 list_add_head(&gdi_font_list, &font->entry);
4351 /*************************************************************
4352 * create_child_font_list
4354 static BOOL create_child_font_list(GdiFont *font)
4357 SYSTEM_LINKS *font_link;
4358 CHILD_FONT *font_link_entry, *new_child;
4362 psub = get_font_subst(&font_subst_list, font->name, -1);
4363 font_name = psub ? psub->to.name : font->name;
4364 font_link = find_font_link(font_name);
4365 if (font_link != NULL)
4367 TRACE("found entry in system list\n");
4368 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4370 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4371 new_child->face = font_link_entry->face;
4372 new_child->font = NULL;
4373 list_add_tail(&font->child_fonts, &new_child->entry);
4374 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4379 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4380 * Sans Serif. This is how asian windows get default fallbacks for fonts
4382 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4383 font->charset != OEM_CHARSET &&
4384 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4386 font_link = find_font_link(szDefaultFallbackLink);
4387 if (font_link != NULL)
4389 TRACE("found entry in default fallback list\n");
4390 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4392 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4393 new_child->face = font_link_entry->face;
4394 new_child->font = NULL;
4395 list_add_tail(&font->child_fonts, &new_child->entry);
4396 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4405 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4407 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4409 if (pFT_Set_Charmap)
4412 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4414 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4416 for (i = 0; i < ft_face->num_charmaps; i++)
4418 if (ft_face->charmaps[i]->encoding == encoding)
4420 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4421 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4423 switch (ft_face->charmaps[i]->platform_id)
4426 cmap_def = ft_face->charmaps[i];
4428 case 0: /* Apple Unicode */
4429 cmap0 = ft_face->charmaps[i];
4431 case 1: /* Macintosh */
4432 cmap1 = ft_face->charmaps[i];
4435 cmap2 = ft_face->charmaps[i];
4437 case 3: /* Microsoft */
4438 cmap3 = ft_face->charmaps[i];
4443 if (cmap3) /* prefer Microsoft cmap table */
4444 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4446 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4448 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4450 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4452 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4454 return ft_err == FT_Err_Ok;
4457 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4461 /*************************************************************
4464 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4465 LPCWSTR output, const DEVMODEW *devmode )
4467 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4469 if (!physdev) return FALSE;
4470 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4475 /*************************************************************
4478 static BOOL freetype_DeleteDC( PHYSDEV dev )
4480 struct freetype_physdev *physdev = get_freetype_dev( dev );
4481 HeapFree( GetProcessHeap(), 0, physdev );
4485 static FT_Encoding pick_charmap( FT_Face face, int charset )
4487 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4488 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4489 const FT_Encoding *encs = regular_order;
4491 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4495 if (select_charmap( face, *encs )) break;
4501 #define GASP_GRIDFIT 0x01
4502 #define GASP_DOGRAY 0x02
4503 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4505 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4508 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4509 WORD *alloced = NULL, *ptr = buf;
4510 WORD num_recs, version;
4514 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4515 if (size == GDI_ERROR) return FALSE;
4516 if (size < 4 * sizeof(WORD)) return FALSE;
4517 if (size > sizeof(buf))
4519 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4520 if (!ptr) return FALSE;
4523 get_font_data( font, GASP_TAG, 0, ptr, size );
4525 version = GET_BE_WORD( *ptr++ );
4526 num_recs = GET_BE_WORD( *ptr++ );
4528 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4530 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4536 *flags = GET_BE_WORD( *(ptr + 1) );
4537 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4540 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4544 HeapFree( GetProcessHeap(), 0, alloced );
4548 /*************************************************************
4549 * freetype_SelectFont
4551 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4553 struct freetype_physdev *physdev = get_freetype_dev( dev );
4555 Face *face, *best, *best_bitmap;
4556 Family *family, *last_resort_family;
4557 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4558 INT height, width = 0;
4559 unsigned int score = 0, new_score;
4560 signed int diff = 0, newdiff;
4561 BOOL bd, it, can_use_bitmap, want_vertical;
4566 FontSubst *psub = NULL;
4567 DC *dc = get_dc_ptr( dev->hdc );
4568 const SYSTEM_LINKS *font_link;
4570 if (!hfont) /* notification that the font has been changed by another driver */
4573 physdev->font = NULL;
4574 release_dc_ptr( dc );
4578 GetObjectW( hfont, sizeof(lf), &lf );
4579 lf.lfWidth = abs(lf.lfWidth);
4581 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4583 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4584 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4585 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4588 if(dc->GraphicsMode == GM_ADVANCED)
4590 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4591 /* Try to avoid not necessary glyph transformations */
4592 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4594 lf.lfHeight *= fabs(dcmat.eM11);
4595 lf.lfWidth *= fabs(dcmat.eM11);
4596 dcmat.eM11 = dcmat.eM22 = 1.0;
4601 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4602 font scaling abilities. */
4603 dcmat.eM11 = dcmat.eM22 = 1.0;
4604 dcmat.eM21 = dcmat.eM12 = 0;
4605 if (dc->vport2WorldValid)
4607 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4608 lf.lfOrientation = -lf.lfOrientation;
4609 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4610 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4614 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4615 dcmat.eM21, dcmat.eM22);
4618 EnterCriticalSection( &freetype_cs );
4620 /* check the cache first */
4621 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4622 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4626 if(list_empty(&font_list)) /* No fonts installed */
4628 TRACE("No fonts installed\n");
4632 TRACE("not in cache\n");
4635 ret->font_desc.matrix = dcmat;
4636 ret->font_desc.lf = lf;
4637 ret->font_desc.can_use_bitmap = can_use_bitmap;
4638 calc_hash(&ret->font_desc);
4639 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4640 hflist->hfont = hfont;
4641 list_add_head(&ret->hfontlist, &hflist->entry);
4643 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4644 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4645 original value lfCharSet. Note this is a special case for
4646 Symbol and doesn't happen at least for "Wingdings*" */
4648 if(!strcmpiW(lf.lfFaceName, SymbolW))
4649 lf.lfCharSet = SYMBOL_CHARSET;
4651 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4652 switch(lf.lfCharSet) {
4653 case DEFAULT_CHARSET:
4654 csi.fs.fsCsb[0] = 0;
4657 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4658 csi.fs.fsCsb[0] = 0;
4664 if(lf.lfFaceName[0] != '\0') {
4665 CHILD_FONT *font_link_entry;
4666 LPWSTR FaceName = lf.lfFaceName;
4668 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4671 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4672 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4673 if (psub->to.charset != -1)
4674 lf.lfCharSet = psub->to.charset;
4677 /* We want a match on name and charset or just name if
4678 charset was DEFAULT_CHARSET. If the latter then
4679 we fixup the returned charset later in get_nearest_charset
4680 where we'll either use the charset of the current ansi codepage
4681 or if that's unavailable the first charset that the font supports.
4683 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4684 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4685 if (!strcmpiW(family->FamilyName, FaceName) ||
4686 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4688 font_link = find_font_link(family->FamilyName);
4689 face_list = get_face_list_from_family(family);
4690 LIST_FOR_EACH(face_elem_ptr, face_list) {
4691 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4692 if (!(face->scalable || can_use_bitmap))
4694 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4696 if (font_link != NULL &&
4697 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4699 if (!csi.fs.fsCsb[0])
4705 /* Search by full face name. */
4706 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4707 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4708 face_list = get_face_list_from_family(family);
4709 LIST_FOR_EACH(face_elem_ptr, face_list) {
4710 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4711 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4712 (face->scalable || can_use_bitmap))
4714 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4716 font_link = find_font_link(family->FamilyName);
4717 if (font_link != NULL &&
4718 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4725 * Try check the SystemLink list first for a replacement font.
4726 * We may find good replacements there.
4728 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4730 if(!strcmpiW(font_link->font_name, FaceName) ||
4731 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4733 TRACE("found entry in system list\n");
4734 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4736 const SYSTEM_LINKS *links;
4738 face = font_link_entry->face;
4739 if (!(face->scalable || can_use_bitmap))
4741 family = face->family;
4742 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4744 links = find_font_link(family->FamilyName);
4745 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4752 psub = NULL; /* substitution is no more relevant */
4754 /* If requested charset was DEFAULT_CHARSET then try using charset
4755 corresponding to the current ansi codepage */
4756 if (!csi.fs.fsCsb[0])
4759 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4760 FIXME("TCI failed on codepage %d\n", acp);
4761 csi.fs.fsCsb[0] = 0;
4763 lf.lfCharSet = csi.ciCharset;
4766 want_vertical = (lf.lfFaceName[0] == '@');
4768 /* Face families are in the top 4 bits of lfPitchAndFamily,
4769 so mask with 0xF0 before testing */
4771 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4772 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4773 strcpyW(lf.lfFaceName, defFixed);
4774 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4775 strcpyW(lf.lfFaceName, defSerif);
4776 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4777 strcpyW(lf.lfFaceName, defSans);
4779 strcpyW(lf.lfFaceName, defSans);
4780 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4781 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4782 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4783 font_link = find_font_link(family->FamilyName);
4784 face_list = get_face_list_from_family(family);
4785 LIST_FOR_EACH(face_elem_ptr, face_list) {
4786 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4787 if (!(face->scalable || can_use_bitmap))
4789 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4791 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4797 last_resort_family = NULL;
4798 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4799 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4800 font_link = find_font_link(family->FamilyName);
4801 face_list = get_face_list_from_family(family);
4802 LIST_FOR_EACH(face_elem_ptr, face_list) {
4803 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4804 if(face->vertical == want_vertical &&
4805 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4806 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4809 if(can_use_bitmap && !last_resort_family)
4810 last_resort_family = family;
4815 if(last_resort_family) {
4816 family = last_resort_family;
4817 csi.fs.fsCsb[0] = 0;
4821 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4822 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4823 face_list = get_face_list_from_family(family);
4824 LIST_FOR_EACH(face_elem_ptr, face_list) {
4825 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4826 if(face->scalable && face->vertical == want_vertical) {
4827 csi.fs.fsCsb[0] = 0;
4828 WARN("just using first face for now\n");
4831 if(can_use_bitmap && !last_resort_family)
4832 last_resort_family = family;
4835 if(!last_resort_family) {
4836 FIXME("can't find a single appropriate font - bailing\n");
4842 WARN("could only find a bitmap font - this will probably look awful!\n");
4843 family = last_resort_family;
4844 csi.fs.fsCsb[0] = 0;
4847 it = lf.lfItalic ? 1 : 0;
4848 bd = lf.lfWeight > 550 ? 1 : 0;
4850 height = lf.lfHeight;
4852 face = best = best_bitmap = NULL;
4853 font_link = find_font_link(family->FamilyName);
4854 face_list = get_face_list_from_family(family);
4855 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4857 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4858 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4863 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4864 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4865 new_score = (italic ^ it) + (bold ^ bd);
4866 if(!best || new_score <= score)
4868 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4869 italic, bold, it, bd);
4872 if(best->scalable && score == 0) break;
4876 newdiff = height - (signed int)(best->size.height);
4878 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4879 if(!best_bitmap || new_score < score ||
4880 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4882 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4885 if(score == 0 && diff == 0) break;
4892 face = best->scalable ? best : best_bitmap;
4893 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4894 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4897 height = lf.lfHeight;
4901 if(csi.fs.fsCsb[0]) {
4902 ret->charset = lf.lfCharSet;
4903 ret->codepage = csi.ciACP;
4906 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4908 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4909 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
4911 ret->aveWidth = height ? lf.lfWidth : 0;
4913 if(!face->scalable) {
4914 /* Windows uses integer scaling factors for bitmap fonts */
4915 INT scale, scaled_height;
4916 GdiFont *cachedfont;
4918 /* FIXME: rotation of bitmap fonts is ignored */
4919 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4921 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4922 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4923 dcmat.eM11 = dcmat.eM22 = 1.0;
4924 /* As we changed the matrix, we need to search the cache for the font again,
4925 * otherwise we might explode the cache. */
4926 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4927 TRACE("Found cached font after non-scalable matrix rescale!\n");
4932 calc_hash(&ret->font_desc);
4934 if (height != 0) height = diff;
4935 height += face->size.height;
4937 scale = (height + face->size.height - 1) / face->size.height;
4938 scaled_height = scale * face->size.height;
4939 /* Only jump to the next height if the difference <= 25% original height */
4940 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4941 /* The jump between unscaled and doubled is delayed by 1 */
4942 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4943 ret->scale_y = scale;
4945 width = face->size.x_ppem >> 6;
4946 height = face->size.y_ppem >> 6;
4950 TRACE("font scale y: %f\n", ret->scale_y);
4952 ret->ft_face = OpenFontFace(ret, face, width, height);
4961 ret->ntmFlags = face->ntmFlags;
4963 pick_charmap( ret->ft_face, ret->charset );
4965 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4966 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4967 ret->underline = lf.lfUnderline ? 0xff : 0;
4968 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4969 create_child_font_list(ret);
4971 if (face->vertical) /* We need to try to load the GSUB table */
4973 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4974 if (length != GDI_ERROR)
4976 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4977 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4978 TRACE("Loaded GSUB table of %i bytes\n",length);
4981 ret->aa_flags = face->aa_flags;
4983 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4989 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
4991 switch (lf.lfQuality)
4993 case NONANTIALIASED_QUALITY:
4994 case ANTIALIASED_QUALITY:
4995 next->funcs->pSelectFont( dev, hfont, aa_flags );
4997 case CLEARTYPE_QUALITY:
4998 case CLEARTYPE_NATURAL_QUALITY:
5000 if (!*aa_flags) *aa_flags = ret->aa_flags;
5001 next->funcs->pSelectFont( dev, hfont, aa_flags );
5003 /* fixup the antialiasing flags for that font */
5006 case WINE_GGO_HRGB_BITMAP:
5007 case WINE_GGO_HBGR_BITMAP:
5008 case WINE_GGO_VRGB_BITMAP:
5009 case WINE_GGO_VBGR_BITMAP:
5010 if (is_subpixel_rendering_enabled()) break;
5011 *aa_flags = GGO_GRAY4_BITMAP;
5013 case GGO_GRAY2_BITMAP:
5014 case GGO_GRAY4_BITMAP:
5015 case GGO_GRAY8_BITMAP:
5016 case WINE_GGO_GRAY16_BITMAP:
5017 if (is_hinting_enabled())
5020 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5022 TRACE( "font %s %d aa disabled by GASP\n",
5023 debugstr_w(lf.lfFaceName), lf.lfHeight );
5024 *aa_flags = GGO_BITMAP;
5029 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5031 physdev->font = ret;
5033 LeaveCriticalSection( &freetype_cs );
5034 release_dc_ptr( dc );
5035 return ret ? hfont : 0;
5038 static void dump_gdi_font_list(void)
5041 struct list *elem_ptr;
5043 TRACE("---------- gdiFont Cache ----------\n");
5044 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
5045 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
5046 TRACE("gdiFont=%p %s %d\n",
5047 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
5050 TRACE("---------- Unused gdiFont Cache ----------\n");
5051 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
5052 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
5053 TRACE("gdiFont=%p %s %d\n",
5054 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
5057 TRACE("---------- Child gdiFont Cache ----------\n");
5058 LIST_FOR_EACH(elem_ptr, &child_font_list) {
5059 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
5060 TRACE("gdiFont=%p %s %d\n",
5061 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
5065 /*************************************************************
5066 * WineEngDestroyFontInstance
5068 * free the gdiFont associated with this handle
5071 BOOL WineEngDestroyFontInstance(HFONT handle)
5076 struct list *font_elem_ptr, *hfontlist_elem_ptr;
5080 EnterCriticalSection( &freetype_cs );
5082 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
5084 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
5085 while(hfontlist_elem_ptr) {
5086 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
5087 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
5088 if(hflist->hfont == handle) {
5089 TRACE("removing child font %p from child list\n", gdiFont);
5090 list_remove(&gdiFont->entry);
5091 LeaveCriticalSection( &freetype_cs );
5097 TRACE("destroying hfont=%p\n", handle);
5099 dump_gdi_font_list();
5101 font_elem_ptr = list_head(&gdi_font_list);
5102 while(font_elem_ptr) {
5103 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
5104 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
5106 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
5107 while(hfontlist_elem_ptr) {
5108 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
5109 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
5110 if(hflist->hfont == handle) {
5111 list_remove(&hflist->entry);
5112 HeapFree(GetProcessHeap(), 0, hflist);
5116 if(list_empty(&gdiFont->hfontlist)) {
5117 TRACE("Moving to Unused list\n");
5118 list_remove(&gdiFont->entry);
5119 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
5124 font_elem_ptr = list_head(&unused_gdi_font_list);
5125 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
5126 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
5127 while(font_elem_ptr) {
5128 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
5129 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
5130 TRACE("freeing %p\n", gdiFont);
5131 list_remove(&gdiFont->entry);
5134 LeaveCriticalSection( &freetype_cs );
5138 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5145 id += IDS_FIRST_SCRIPT;
5146 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5147 if (!rsrc) return 0;
5148 hMem = LoadResource( gdi32_module, rsrc );
5149 if (!hMem) return 0;
5151 p = LockResource( hMem );
5153 while (id--) p += *p + 1;
5155 i = min(LF_FACESIZE - 1, *p);
5156 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5162 /***************************************************
5163 * create_enum_charset_list
5165 * This function creates charset enumeration list because in DEFAULT_CHARSET
5166 * case, the ANSI codepage's charset takes precedence over other charsets.
5167 * This function works as a filter other than DEFAULT_CHARSET case.
5169 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5174 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5175 csi.fs.fsCsb[0] != 0) {
5176 list->element[n].mask = csi.fs.fsCsb[0];
5177 list->element[n].charset = csi.ciCharset;
5178 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5181 else { /* charset is DEFAULT_CHARSET or invalid. */
5185 /* Set the current codepage's charset as the first element. */
5187 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5188 csi.fs.fsCsb[0] != 0) {
5189 list->element[n].mask = csi.fs.fsCsb[0];
5190 list->element[n].charset = csi.ciCharset;
5191 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5192 mask |= csi.fs.fsCsb[0];
5196 /* Fill out left elements. */
5197 for (i = 0; i < 32; i++) {
5199 fs.fsCsb[0] = 1L << i;
5201 if (fs.fsCsb[0] & mask)
5202 continue; /* skip, already added. */
5203 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5204 continue; /* skip, this is an invalid fsCsb bit. */
5206 list->element[n].mask = fs.fsCsb[0];
5207 list->element[n].charset = csi.ciCharset;
5208 load_script_name( i, list->element[n].name );
5209 mask |= fs.fsCsb[0];
5213 /* add catch all mask for remaining bits */
5216 list->element[n].mask = ~mask;
5217 list->element[n].charset = DEFAULT_CHARSET;
5218 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5227 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5228 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5233 if (face->cached_enum_data)
5236 *pelf = face->cached_enum_data->elf;
5237 *pntm = face->cached_enum_data->ntm;
5238 *ptype = face->cached_enum_data->type;
5242 font = alloc_font();
5244 if(face->scalable) {
5248 height = face->size.y_ppem >> 6;
5249 width = face->size.x_ppem >> 6;
5251 font->scale_y = 1.0;
5253 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5259 font->name = strdupW(face->family->FamilyName);
5260 font->ntmFlags = face->ntmFlags;
5262 if (get_outline_text_metrics(font))
5264 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5266 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5267 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5268 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5270 lstrcpynW(pelf->elfLogFont.lfFaceName,
5271 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5273 lstrcpynW(pelf->elfFullName,
5274 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5276 lstrcpynW(pelf->elfStyle,
5277 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5282 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5284 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5285 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5286 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5288 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5290 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5292 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5293 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5296 pntm->ntmTm.ntmFlags = face->ntmFlags;
5297 pntm->ntmFontSig = face->fs;
5299 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5301 pelf->elfLogFont.lfEscapement = 0;
5302 pelf->elfLogFont.lfOrientation = 0;
5303 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5304 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5305 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5306 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5307 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5308 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5309 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5310 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5311 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5312 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5313 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5316 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5317 *ptype |= TRUETYPE_FONTTYPE;
5318 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5319 *ptype |= DEVICE_FONTTYPE;
5320 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5321 *ptype |= RASTER_FONTTYPE;
5323 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5324 if (face->cached_enum_data)
5326 face->cached_enum_data->elf = *pelf;
5327 face->cached_enum_data->ntm = *pntm;
5328 face->cached_enum_data->type = *ptype;
5334 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5336 const struct list *face_list, *face_elem_ptr;
5338 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5340 face_list = get_face_list_from_family(family);
5341 LIST_FOR_EACH(face_elem_ptr, face_list)
5343 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5345 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5351 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5353 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5355 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5358 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5359 FONTENUMPROCW proc, LPARAM lparam)
5362 NEWTEXTMETRICEXW ntm;
5366 GetEnumStructs(face, &elf, &ntm, &type);
5367 for(i = 0; i < list->total; i++) {
5368 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5369 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5370 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5371 i = list->total; /* break out of loop after enumeration */
5375 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5376 /* use the DEFAULT_CHARSET case only if no other charset is present */
5377 if (list->element[i].charset == DEFAULT_CHARSET &&
5378 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5379 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5380 strcpyW(elf.elfScript, list->element[i].name);
5381 if (!elf.elfScript[0])
5382 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5384 /* Font Replacement */
5385 if (family != face->family)
5387 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5389 strcpyW(elf.elfFullName, face->FullName);
5391 strcpyW(elf.elfFullName, family->FamilyName);
5393 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5394 debugstr_w(elf.elfLogFont.lfFaceName),
5395 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5396 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5397 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5398 ntm.ntmTm.ntmFlags);
5399 /* release section before callback (FIXME) */
5400 LeaveCriticalSection( &freetype_cs );
5401 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5402 EnterCriticalSection( &freetype_cs );
5407 /*************************************************************
5408 * freetype_EnumFonts
5410 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5414 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5416 struct enum_charset_list enum_charsets;
5420 lf.lfCharSet = DEFAULT_CHARSET;
5421 lf.lfPitchAndFamily = 0;
5422 lf.lfFaceName[0] = 0;
5426 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5428 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5431 EnterCriticalSection( &freetype_cs );
5432 if(plf->lfFaceName[0]) {
5434 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5437 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5438 debugstr_w(psub->to.name));
5440 strcpyW(lf.lfFaceName, psub->to.name);
5444 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5445 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5446 if(family_matches(family, plf)) {
5447 face_list = get_face_list_from_family(family);
5448 LIST_FOR_EACH(face_elem_ptr, face_list) {
5449 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5450 if (!face_matches(family->FamilyName, face, plf)) continue;
5451 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5456 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5457 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5458 face_list = get_face_list_from_family(family);
5459 face_elem_ptr = list_head(face_list);
5460 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5461 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5464 LeaveCriticalSection( &freetype_cs );
5468 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5470 pt->x.value = vec->x >> 6;
5471 pt->x.fract = (vec->x & 0x3f) << 10;
5472 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5473 pt->y.value = vec->y >> 6;
5474 pt->y.fract = (vec->y & 0x3f) << 10;
5475 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5479 /***************************************************
5480 * According to the MSDN documentation on WideCharToMultiByte,
5481 * certain codepages cannot set the default_used parameter.
5482 * This returns TRUE if the codepage can set that parameter, false else
5483 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5485 static BOOL codepage_sets_default_used(UINT codepage)
5499 * GSUB Table handling functions
5502 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5504 const GSUB_CoverageFormat1* cf1;
5508 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5510 int count = GET_BE_WORD(cf1->GlyphCount);
5512 TRACE("Coverage Format 1, %i glyphs\n",count);
5513 for (i = 0; i < count; i++)
5514 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5518 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5520 const GSUB_CoverageFormat2* cf2;
5523 cf2 = (const GSUB_CoverageFormat2*)cf1;
5525 count = GET_BE_WORD(cf2->RangeCount);
5526 TRACE("Coverage Format 2, %i ranges\n",count);
5527 for (i = 0; i < count; i++)
5529 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5531 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5532 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5534 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5535 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5541 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5546 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5548 const GSUB_ScriptList *script;
5549 const GSUB_Script *deflt = NULL;
5551 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5553 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5554 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5556 const GSUB_Script *scr;
5559 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5560 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5562 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5564 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5570 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5574 const GSUB_LangSys *Lang;
5576 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5578 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5580 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5581 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5583 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5586 offset = GET_BE_WORD(script->DefaultLangSys);
5589 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5595 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5598 const GSUB_FeatureList *feature;
5599 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5601 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5602 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5604 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5605 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5607 const GSUB_Feature *feat;
5608 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5615 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5619 const GSUB_LookupList *lookup;
5620 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5622 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5623 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5625 const GSUB_LookupTable *look;
5626 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5627 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5628 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5629 if (GET_BE_WORD(look->LookupType) != 1)
5630 FIXME("We only handle SubType 1\n");
5635 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5637 const GSUB_SingleSubstFormat1 *ssf1;
5638 offset = GET_BE_WORD(look->SubTable[j]);
5639 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5640 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5642 int offset = GET_BE_WORD(ssf1->Coverage);
5643 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5644 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5646 TRACE(" Glyph 0x%x ->",glyph);
5647 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5648 TRACE(" 0x%x\n",glyph);
5653 const GSUB_SingleSubstFormat2 *ssf2;
5657 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5658 offset = GET_BE_WORD(ssf1->Coverage);
5659 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5660 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5661 TRACE(" Coverage index %i\n",index);
5664 TRACE(" Glyph is 0x%x ->",glyph);
5665 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5666 TRACE("0x%x\n",glyph);
5675 static const char* get_opentype_script(const GdiFont *font)
5678 * I am not sure if this is the correct way to generate our script tag
5681 switch (font->charset)
5683 case ANSI_CHARSET: return "latn";
5684 case BALTIC_CHARSET: return "latn"; /* ?? */
5685 case CHINESEBIG5_CHARSET: return "hani";
5686 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5687 case GB2312_CHARSET: return "hani";
5688 case GREEK_CHARSET: return "grek";
5689 case HANGUL_CHARSET: return "hang";
5690 case RUSSIAN_CHARSET: return "cyrl";
5691 case SHIFTJIS_CHARSET: return "kana";
5692 case TURKISH_CHARSET: return "latn"; /* ?? */
5693 case VIETNAMESE_CHARSET: return "latn";
5694 case JOHAB_CHARSET: return "latn"; /* ?? */
5695 case ARABIC_CHARSET: return "arab";
5696 case HEBREW_CHARSET: return "hebr";
5697 case THAI_CHARSET: return "thai";
5698 default: return "latn";
5702 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5704 const GSUB_Header *header;
5705 const GSUB_Script *script;
5706 const GSUB_LangSys *language;
5707 const GSUB_Feature *feature;
5709 if (!font->GSUB_Table)
5712 header = font->GSUB_Table;
5714 script = GSUB_get_script_table(header, get_opentype_script(font));
5717 TRACE("Script not found\n");
5720 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5723 TRACE("Language not found\n");
5726 feature = GSUB_get_feature(header, language, "vrt2");
5728 feature = GSUB_get_feature(header, language, "vert");
5731 TRACE("vrt2/vert feature not found\n");
5734 return GSUB_apply_feature(header, feature, glyph);
5737 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5741 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5742 WCHAR wc = (WCHAR)glyph;
5744 BOOL *default_used_pointer;
5747 default_used_pointer = NULL;
5748 default_used = FALSE;
5749 if (codepage_sets_default_used(font->codepage))
5750 default_used_pointer = &default_used;
5751 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5753 if (font->codepage == CP_SYMBOL && wc < 0x100)
5754 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5759 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5760 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5764 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5766 if (glyph < 0x100) glyph += 0xf000;
5767 /* there is a number of old pre-Unicode "broken" TTFs, which
5768 do have symbols at U+00XX instead of U+f0XX */
5769 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5770 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5772 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5777 /*************************************************************
5778 * freetype_GetGlyphIndices
5780 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5782 struct freetype_physdev *physdev = get_freetype_dev( dev );
5785 BOOL got_default = FALSE;
5789 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5790 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5793 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5795 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5800 EnterCriticalSection( &freetype_cs );
5802 for(i = 0; i < count; i++)
5804 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5809 if (FT_IS_SFNT(physdev->font->ft_face))
5811 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5812 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5817 get_text_metrics(physdev->font, &textm);
5818 default_char = textm.tmDefaultChar;
5822 pgi[i] = default_char;
5825 LeaveCriticalSection( &freetype_cs );
5829 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5831 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5832 return !memcmp(matrix, &identity, sizeof(FMAT2));
5835 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5837 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5838 return !memcmp(matrix, &identity, sizeof(MAT2));
5841 static inline BYTE get_max_level( UINT format )
5845 case GGO_GRAY2_BITMAP: return 4;
5846 case GGO_GRAY4_BITMAP: return 16;
5847 case GGO_GRAY8_BITMAP: return 64;
5852 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5854 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5855 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5858 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5859 FT_Face ft_face = incoming_font->ft_face;
5860 GdiFont *font = incoming_font;
5861 FT_UInt glyph_index;
5862 DWORD width, height, pitch, needed = 0;
5863 FT_Bitmap ft_bitmap;
5865 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5867 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5868 double widthRatio = 1.0;
5869 FT_Matrix transMat = identityMat;
5870 FT_Matrix transMatUnrotated;
5871 BOOL needsTransform = FALSE;
5872 BOOL tategaki = (font->GSUB_Table != NULL);
5873 UINT original_index;
5875 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5876 buflen, buf, lpmat);
5878 TRACE("font transform %f %f %f %f\n",
5879 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5880 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5882 if(format & GGO_GLYPH_INDEX) {
5883 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5884 original_index = glyph;
5885 format &= ~GGO_GLYPH_INDEX;
5887 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5888 ft_face = font->ft_face;
5889 original_index = glyph_index;
5892 if(format & GGO_UNHINTED) {
5893 load_flags |= FT_LOAD_NO_HINTING;
5894 format &= ~GGO_UNHINTED;
5897 /* tategaki never appears to happen to lower glyph index */
5898 if (glyph_index < TATEGAKI_LOWER_BOUND )
5901 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5902 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5903 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5904 font->gmsize * sizeof(GM*));
5906 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5907 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5909 *lpgm = FONT_GM(font,original_index)->gm;
5910 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5911 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5912 lpgm->gmCellIncX, lpgm->gmCellIncY);
5913 return 1; /* FIXME */
5917 if (!font->gm[original_index / GM_BLOCK_SIZE])
5918 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5920 /* Scaling factor */
5925 get_text_metrics(font, &tm);
5927 widthRatio = (double)font->aveWidth;
5928 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5931 widthRatio = font->scale_y;
5933 /* Scaling transform */
5934 if (widthRatio != 1.0 || font->scale_y != 1.0)
5937 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5940 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5942 pFT_Matrix_Multiply(&scaleMat, &transMat);
5943 needsTransform = TRUE;
5946 /* Slant transform */
5947 if (font->fake_italic) {
5950 slantMat.xx = (1 << 16);
5951 slantMat.xy = ((1 << 16) >> 2);
5953 slantMat.yy = (1 << 16);
5954 pFT_Matrix_Multiply(&slantMat, &transMat);
5955 needsTransform = TRUE;
5958 /* Rotation transform */
5959 transMatUnrotated = transMat;
5960 if(font->orientation && !tategaki) {
5961 FT_Matrix rotationMat;
5963 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5964 pFT_Vector_Unit(&vecAngle, angle);
5965 rotationMat.xx = vecAngle.x;
5966 rotationMat.xy = -vecAngle.y;
5967 rotationMat.yx = -rotationMat.xy;
5968 rotationMat.yy = rotationMat.xx;
5970 pFT_Matrix_Multiply(&rotationMat, &transMat);
5971 needsTransform = TRUE;
5974 /* World transform */
5975 if (!is_identity_FMAT2(&font->font_desc.matrix))
5978 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5979 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5980 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5981 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5982 pFT_Matrix_Multiply(&worldMat, &transMat);
5983 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5984 needsTransform = TRUE;
5987 /* Extra transformation specified by caller */
5988 if (!is_identity_MAT2(lpmat))
5991 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5992 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5993 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5994 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5995 pFT_Matrix_Multiply(&extraMat, &transMat);
5996 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5997 needsTransform = TRUE;
6000 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6002 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6005 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6009 if(!needsTransform) {
6010 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
6011 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
6012 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
6014 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
6015 bottom = (ft_face->glyph->metrics.horiBearingY -
6016 ft_face->glyph->metrics.height) & -64;
6017 lpgm->gmCellIncX = adv;
6018 lpgm->gmCellIncY = 0;
6025 for(xc = 0; xc < 2; xc++) {
6026 for(yc = 0; yc < 2; yc++) {
6027 vec.x = (ft_face->glyph->metrics.horiBearingX +
6028 xc * ft_face->glyph->metrics.width);
6029 vec.y = ft_face->glyph->metrics.horiBearingY -
6030 yc * ft_face->glyph->metrics.height;
6031 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6032 pFT_Vector_Transform(&vec, &transMat);
6033 if(xc == 0 && yc == 0) {
6034 left = right = vec.x;
6035 top = bottom = vec.y;
6037 if(vec.x < left) left = vec.x;
6038 else if(vec.x > right) right = vec.x;
6039 if(vec.y < bottom) bottom = vec.y;
6040 else if(vec.y > top) top = vec.y;
6045 right = (right + 63) & -64;
6046 bottom = bottom & -64;
6047 top = (top + 63) & -64;
6049 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6050 vec.x = ft_face->glyph->metrics.horiAdvance;
6052 pFT_Vector_Transform(&vec, &transMat);
6053 lpgm->gmCellIncX = (vec.x+63) >> 6;
6054 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6056 vec.x = ft_face->glyph->metrics.horiAdvance;
6058 pFT_Vector_Transform(&vec, &transMatUnrotated);
6059 adv = (vec.x+63) >> 6;
6063 bbx = (right - left) >> 6;
6064 lpgm->gmBlackBoxX = (right - left) >> 6;
6065 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6066 lpgm->gmptGlyphOrigin.x = left >> 6;
6067 lpgm->gmptGlyphOrigin.y = top >> 6;
6069 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6070 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6071 lpgm->gmCellIncX, lpgm->gmCellIncY);
6073 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6074 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6076 FONT_GM(font,original_index)->gm = *lpgm;
6077 FONT_GM(font,original_index)->adv = adv;
6078 FONT_GM(font,original_index)->lsb = lsb;
6079 FONT_GM(font,original_index)->bbx = bbx;
6080 FONT_GM(font,original_index)->init = TRUE;
6083 if(format == GGO_METRICS)
6085 return 1; /* FIXME */
6088 if(ft_face->glyph->format != ft_glyph_format_outline &&
6089 (format == GGO_NATIVE || format == GGO_BEZIER))
6091 TRACE("loaded a bitmap\n");
6097 width = lpgm->gmBlackBoxX;
6098 height = lpgm->gmBlackBoxY;
6099 pitch = ((width + 31) >> 5) << 2;
6100 needed = pitch * height;
6102 if(!buf || !buflen) break;
6104 switch(ft_face->glyph->format) {
6105 case ft_glyph_format_bitmap:
6107 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6108 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
6109 INT h = ft_face->glyph->bitmap.rows;
6111 memcpy(dst, src, w);
6112 src += ft_face->glyph->bitmap.pitch;
6118 case ft_glyph_format_outline:
6119 ft_bitmap.width = width;
6120 ft_bitmap.rows = height;
6121 ft_bitmap.pitch = pitch;
6122 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6123 ft_bitmap.buffer = buf;
6126 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6128 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6130 /* Note: FreeType will only set 'black' bits for us. */
6131 memset(buf, 0, needed);
6132 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6136 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6141 case GGO_GRAY2_BITMAP:
6142 case GGO_GRAY4_BITMAP:
6143 case GGO_GRAY8_BITMAP:
6144 case WINE_GGO_GRAY16_BITMAP:
6146 unsigned int max_level, row, col;
6149 width = lpgm->gmBlackBoxX;
6150 height = lpgm->gmBlackBoxY;
6151 pitch = (width + 3) / 4 * 4;
6152 needed = pitch * height;
6154 if(!buf || !buflen) break;
6156 max_level = get_max_level( format );
6158 switch(ft_face->glyph->format) {
6159 case ft_glyph_format_bitmap:
6161 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6162 INT h = ft_face->glyph->bitmap.rows;
6164 memset( buf, 0, needed );
6166 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6167 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6168 src += ft_face->glyph->bitmap.pitch;
6173 case ft_glyph_format_outline:
6175 ft_bitmap.width = width;
6176 ft_bitmap.rows = height;
6177 ft_bitmap.pitch = pitch;
6178 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6179 ft_bitmap.buffer = buf;
6182 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6184 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6186 memset(ft_bitmap.buffer, 0, buflen);
6188 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6190 if (max_level != 255)
6192 for (row = 0, start = buf; row < height; row++)
6194 for (col = 0, ptr = start; col < width; col++, ptr++)
6195 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6203 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6209 case WINE_GGO_HRGB_BITMAP:
6210 case WINE_GGO_HBGR_BITMAP:
6211 case WINE_GGO_VRGB_BITMAP:
6212 case WINE_GGO_VBGR_BITMAP:
6213 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6215 switch (ft_face->glyph->format)
6217 case FT_GLYPH_FORMAT_BITMAP:
6222 width = lpgm->gmBlackBoxX;
6223 height = lpgm->gmBlackBoxY;
6225 needed = pitch * height;
6227 if (!buf || !buflen) break;
6229 memset(buf, 0, buflen);
6231 src = ft_face->glyph->bitmap.buffer;
6232 src_pitch = ft_face->glyph->bitmap.pitch;
6234 height = min( height, ft_face->glyph->bitmap.rows );
6237 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6239 if ( src[x / 8] & masks[x % 8] )
6240 ((unsigned int *)dst)[x] = ~0u;
6249 case FT_GLYPH_FORMAT_OUTLINE:
6253 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6254 INT x_shift, y_shift;
6256 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6257 FT_Render_Mode render_mode =
6258 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6259 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6261 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6263 if ( render_mode == FT_RENDER_MODE_LCD)
6265 lpgm->gmBlackBoxX += 2;
6266 lpgm->gmptGlyphOrigin.x -= 1;
6270 lpgm->gmBlackBoxY += 2;
6271 lpgm->gmptGlyphOrigin.y += 1;
6275 width = lpgm->gmBlackBoxX;
6276 height = lpgm->gmBlackBoxY;
6278 needed = pitch * height;
6280 if (!buf || !buflen) break;
6282 memset(buf, 0, buflen);
6284 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6286 if ( needsTransform )
6287 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6289 if ( pFT_Library_SetLcdFilter )
6290 pFT_Library_SetLcdFilter( library, lcdfilter );
6291 pFT_Render_Glyph (ft_face->glyph, render_mode);
6293 src = ft_face->glyph->bitmap.buffer;
6294 src_pitch = ft_face->glyph->bitmap.pitch;
6295 src_width = ft_face->glyph->bitmap.width;
6296 src_height = ft_face->glyph->bitmap.rows;
6298 if ( render_mode == FT_RENDER_MODE_LCD)
6306 rgb_interval = src_pitch;
6311 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6312 if ( x_shift < 0 ) x_shift = 0;
6313 if ( x_shift + (src_width / hmul) > width )
6314 x_shift = width - (src_width / hmul);
6316 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6317 if ( y_shift < 0 ) y_shift = 0;
6318 if ( y_shift + (src_height / vmul) > height )
6319 y_shift = height - (src_height / vmul);
6321 dst += x_shift + y_shift * ( pitch / 4 );
6322 while ( src_height )
6324 for ( x = 0; x < src_width / hmul; x++ )
6328 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6329 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6330 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6331 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6335 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6336 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6337 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6338 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6341 src += src_pitch * vmul;
6350 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6362 int contour, point = 0, first_pt;
6363 FT_Outline *outline = &ft_face->glyph->outline;
6364 TTPOLYGONHEADER *pph;
6366 DWORD pph_start, cpfx, type;
6368 if(buflen == 0) buf = NULL;
6370 if (needsTransform && buf) {
6371 pFT_Outline_Transform(outline, &transMat);
6374 for(contour = 0; contour < outline->n_contours; contour++) {
6375 /* Ignore contours containing one point */
6376 if(point == outline->contours[contour]) {
6382 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6385 pph->dwType = TT_POLYGON_TYPE;
6386 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6388 needed += sizeof(*pph);
6390 while(point <= outline->contours[contour]) {
6391 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6392 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6393 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6397 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6400 } while(point <= outline->contours[contour] &&
6401 (outline->tags[point] & FT_Curve_Tag_On) ==
6402 (outline->tags[point-1] & FT_Curve_Tag_On));
6403 /* At the end of a contour Windows adds the start point, but
6405 if(point > outline->contours[contour] &&
6406 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6408 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6410 } else if(point <= outline->contours[contour] &&
6411 outline->tags[point] & FT_Curve_Tag_On) {
6412 /* add closing pt for bezier */
6414 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6422 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6425 pph->cb = needed - pph_start;
6431 /* Convert the quadratic Beziers to cubic Beziers.
6432 The parametric eqn for a cubic Bezier is, from PLRM:
6433 r(t) = at^3 + bt^2 + ct + r0
6434 with the control points:
6439 A quadratic Bezier has the form:
6440 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6442 So equating powers of t leads to:
6443 r1 = 2/3 p1 + 1/3 p0
6444 r2 = 2/3 p1 + 1/3 p2
6445 and of course r0 = p0, r3 = p2
6448 int contour, point = 0, first_pt;
6449 FT_Outline *outline = &ft_face->glyph->outline;
6450 TTPOLYGONHEADER *pph;
6452 DWORD pph_start, cpfx, type;
6453 FT_Vector cubic_control[4];
6454 if(buflen == 0) buf = NULL;
6456 if (needsTransform && buf) {
6457 pFT_Outline_Transform(outline, &transMat);
6460 for(contour = 0; contour < outline->n_contours; contour++) {
6462 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6465 pph->dwType = TT_POLYGON_TYPE;
6466 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6468 needed += sizeof(*pph);
6470 while(point <= outline->contours[contour]) {
6471 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6472 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6473 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6476 if(type == TT_PRIM_LINE) {
6478 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6482 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6485 /* FIXME: Possible optimization in endpoint calculation
6486 if there are two consecutive curves */
6487 cubic_control[0] = outline->points[point-1];
6488 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6489 cubic_control[0].x += outline->points[point].x + 1;
6490 cubic_control[0].y += outline->points[point].y + 1;
6491 cubic_control[0].x >>= 1;
6492 cubic_control[0].y >>= 1;
6494 if(point+1 > outline->contours[contour])
6495 cubic_control[3] = outline->points[first_pt];
6497 cubic_control[3] = outline->points[point+1];
6498 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6499 cubic_control[3].x += outline->points[point].x + 1;
6500 cubic_control[3].y += outline->points[point].y + 1;
6501 cubic_control[3].x >>= 1;
6502 cubic_control[3].y >>= 1;
6505 /* r1 = 1/3 p0 + 2/3 p1
6506 r2 = 1/3 p2 + 2/3 p1 */
6507 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6508 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6509 cubic_control[2] = cubic_control[1];
6510 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6511 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6512 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6513 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6515 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6516 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6517 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6522 } while(point <= outline->contours[contour] &&
6523 (outline->tags[point] & FT_Curve_Tag_On) ==
6524 (outline->tags[point-1] & FT_Curve_Tag_On));
6525 /* At the end of a contour Windows adds the start point,
6526 but only for Beziers and we've already done that.
6528 if(point <= outline->contours[contour] &&
6529 outline->tags[point] & FT_Curve_Tag_On) {
6530 /* This is the closing pt of a bezier, but we've already
6531 added it, so just inc point and carry on */
6538 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6541 pph->cb = needed - pph_start;
6547 FIXME("Unsupported format %d\n", format);
6553 static BOOL get_bitmap_text_metrics(GdiFont *font)
6555 FT_Face ft_face = font->ft_face;
6556 FT_WinFNT_HeaderRec winfnt_header;
6557 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6558 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6559 font->potm->otmSize = size;
6561 #define TM font->potm->otmTextMetrics
6562 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6564 TM.tmHeight = winfnt_header.pixel_height;
6565 TM.tmAscent = winfnt_header.ascent;
6566 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6567 TM.tmInternalLeading = winfnt_header.internal_leading;
6568 TM.tmExternalLeading = winfnt_header.external_leading;
6569 TM.tmAveCharWidth = winfnt_header.avg_width;
6570 TM.tmMaxCharWidth = winfnt_header.max_width;
6571 TM.tmWeight = winfnt_header.weight;
6573 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6574 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6575 TM.tmFirstChar = winfnt_header.first_char;
6576 TM.tmLastChar = winfnt_header.last_char;
6577 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6578 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6579 TM.tmItalic = winfnt_header.italic;
6580 TM.tmUnderlined = font->underline;
6581 TM.tmStruckOut = font->strikeout;
6582 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6583 TM.tmCharSet = winfnt_header.charset;
6587 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6588 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6589 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6590 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6591 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6592 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6593 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6594 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6596 TM.tmDigitizedAspectX = 96; /* FIXME */
6597 TM.tmDigitizedAspectY = 96; /* FIXME */
6599 TM.tmLastChar = 255;
6600 TM.tmDefaultChar = 32;
6601 TM.tmBreakChar = 32;
6602 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6603 TM.tmUnderlined = font->underline;
6604 TM.tmStruckOut = font->strikeout;
6605 /* NB inverted meaning of TMPF_FIXED_PITCH */
6606 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6607 TM.tmCharSet = font->charset;
6615 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6617 double scale_x, scale_y;
6621 scale_x = (double)font->aveWidth;
6622 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6625 scale_x = font->scale_y;
6627 scale_x *= fabs(font->font_desc.matrix.eM11);
6628 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6630 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6631 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6633 SCALE_Y(ptm->tmHeight);
6634 SCALE_Y(ptm->tmAscent);
6635 SCALE_Y(ptm->tmDescent);
6636 SCALE_Y(ptm->tmInternalLeading);
6637 SCALE_Y(ptm->tmExternalLeading);
6638 SCALE_Y(ptm->tmOverhang);
6640 SCALE_X(ptm->tmAveCharWidth);
6641 SCALE_X(ptm->tmMaxCharWidth);
6647 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6649 double scale_x, scale_y;
6653 scale_x = (double)font->aveWidth;
6654 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6657 scale_x = font->scale_y;
6659 scale_x *= fabs(font->font_desc.matrix.eM11);
6660 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6662 scale_font_metrics(font, &potm->otmTextMetrics);
6664 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6665 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6667 SCALE_Y(potm->otmAscent);
6668 SCALE_Y(potm->otmDescent);
6669 SCALE_Y(potm->otmLineGap);
6670 SCALE_Y(potm->otmsCapEmHeight);
6671 SCALE_Y(potm->otmsXHeight);
6672 SCALE_Y(potm->otmrcFontBox.top);
6673 SCALE_Y(potm->otmrcFontBox.bottom);
6674 SCALE_X(potm->otmrcFontBox.left);
6675 SCALE_X(potm->otmrcFontBox.right);
6676 SCALE_Y(potm->otmMacAscent);
6677 SCALE_Y(potm->otmMacDescent);
6678 SCALE_Y(potm->otmMacLineGap);
6679 SCALE_X(potm->otmptSubscriptSize.x);
6680 SCALE_Y(potm->otmptSubscriptSize.y);
6681 SCALE_X(potm->otmptSubscriptOffset.x);
6682 SCALE_Y(potm->otmptSubscriptOffset.y);
6683 SCALE_X(potm->otmptSuperscriptSize.x);
6684 SCALE_Y(potm->otmptSuperscriptSize.y);
6685 SCALE_X(potm->otmptSuperscriptOffset.x);
6686 SCALE_Y(potm->otmptSuperscriptOffset.y);
6687 SCALE_Y(potm->otmsStrikeoutSize);
6688 SCALE_Y(potm->otmsStrikeoutPosition);
6689 SCALE_Y(potm->otmsUnderscoreSize);
6690 SCALE_Y(potm->otmsUnderscorePosition);
6696 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6700 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6702 /* Make sure that the font has sane width/height ratio */
6705 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6707 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6712 *ptm = font->potm->otmTextMetrics;
6713 scale_font_metrics(font, ptm);
6717 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6721 for(i = 0; i < ft_face->num_charmaps; i++)
6723 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6729 static BOOL get_outline_text_metrics(GdiFont *font)
6732 FT_Face ft_face = font->ft_face;
6733 UINT needed, lenfam, lensty, lenface, lenfull;
6735 TT_HoriHeader *pHori;
6736 TT_Postscript *pPost;
6737 FT_Fixed x_scale, y_scale;
6738 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6740 INT ascent, descent;
6742 TRACE("font=%p\n", font);
6744 if(!FT_IS_SCALABLE(ft_face))
6747 needed = sizeof(*font->potm);
6749 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6750 family_nameW = strdupW(font->name);
6752 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6754 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6757 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6758 style_nameW = towstr( CP_ACP, ft_face->style_name );
6760 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6762 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6764 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6767 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6768 face_nameW = strdupW(font->name);
6770 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6771 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6773 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6775 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6778 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6779 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6780 full_nameW = strdupW(fake_nameW);
6782 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6784 /* These names should be read from the TT name table */
6786 /* length of otmpFamilyName */
6789 /* length of otmpFaceName */
6792 /* length of otmpStyleName */
6795 /* length of otmpFullName */
6799 x_scale = ft_face->size->metrics.x_scale;
6800 y_scale = ft_face->size->metrics.y_scale;
6802 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6804 FIXME("Can't find OS/2 table - not TT font?\n");
6808 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6810 FIXME("Can't find HHEA table - not TT font?\n");
6814 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6816 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",
6817 pOS2->usWinAscent, pOS2->usWinDescent,
6818 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6819 pOS2->xAvgCharWidth,
6820 ft_face->ascender, ft_face->descender, ft_face->height,
6821 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6822 ft_face->bbox.yMax, ft_face->bbox.yMin);
6824 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6825 font->potm->otmSize = needed;
6827 #define TM font->potm->otmTextMetrics
6829 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6830 ascent = pHori->Ascender;
6831 descent = -pHori->Descender;
6833 ascent = pOS2->usWinAscent;
6834 descent = pOS2->usWinDescent;
6837 font->ntmCellHeight = ascent + descent;
6838 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6841 TM.tmAscent = font->yMax;
6842 TM.tmDescent = -font->yMin;
6843 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6845 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6846 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6847 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6848 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6851 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6854 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6856 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6857 ((ascent + descent) -
6858 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6860 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6861 if (TM.tmAveCharWidth == 0) {
6862 TM.tmAveCharWidth = 1;
6864 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6865 TM.tmWeight = FW_REGULAR;
6866 if (font->fake_bold)
6867 TM.tmWeight = FW_BOLD;
6870 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6872 if (pOS2->usWeightClass > FW_MEDIUM)
6873 TM.tmWeight = pOS2->usWeightClass;
6875 else if (pOS2->usWeightClass <= FW_MEDIUM)
6876 TM.tmWeight = pOS2->usWeightClass;
6879 TM.tmDigitizedAspectX = 96; /* FIXME */
6880 TM.tmDigitizedAspectY = 96; /* FIXME */
6881 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6882 * symbol range to 0 - f0ff
6885 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6890 case 1257: /* Baltic */
6891 TM.tmLastChar = 0xf8fd;
6894 TM.tmLastChar = 0xf0ff;
6896 TM.tmBreakChar = 0x20;
6897 TM.tmDefaultChar = 0x1f;
6901 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6902 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6904 if(pOS2->usFirstCharIndex <= 1)
6905 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6906 else if (pOS2->usFirstCharIndex > 0xff)
6907 TM.tmBreakChar = 0x20;
6909 TM.tmBreakChar = pOS2->usFirstCharIndex;
6910 TM.tmDefaultChar = TM.tmBreakChar - 1;
6912 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6913 TM.tmUnderlined = font->underline;
6914 TM.tmStruckOut = font->strikeout;
6916 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6917 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6918 (pOS2->version == 0xFFFFU ||
6919 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6920 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6922 TM.tmPitchAndFamily = 0;
6924 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6926 case PAN_FAMILY_SCRIPT:
6927 TM.tmPitchAndFamily |= FF_SCRIPT;
6930 case PAN_FAMILY_DECORATIVE:
6931 TM.tmPitchAndFamily |= FF_DECORATIVE;
6936 case PAN_FAMILY_TEXT_DISPLAY:
6937 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6938 /* which is clearly not what the panose spec says. */
6940 if(TM.tmPitchAndFamily == 0 || /* fixed */
6941 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6942 TM.tmPitchAndFamily = FF_MODERN;
6945 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6950 TM.tmPitchAndFamily |= FF_DONTCARE;
6953 case PAN_SERIF_COVE:
6954 case PAN_SERIF_OBTUSE_COVE:
6955 case PAN_SERIF_SQUARE_COVE:
6956 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6957 case PAN_SERIF_SQUARE:
6958 case PAN_SERIF_THIN:
6959 case PAN_SERIF_BONE:
6960 case PAN_SERIF_EXAGGERATED:
6961 case PAN_SERIF_TRIANGLE:
6962 TM.tmPitchAndFamily |= FF_ROMAN;
6965 case PAN_SERIF_NORMAL_SANS:
6966 case PAN_SERIF_OBTUSE_SANS:
6967 case PAN_SERIF_PERP_SANS:
6968 case PAN_SERIF_FLARED:
6969 case PAN_SERIF_ROUNDED:
6970 TM.tmPitchAndFamily |= FF_SWISS;
6977 if(FT_IS_SCALABLE(ft_face))
6978 TM.tmPitchAndFamily |= TMPF_VECTOR;
6980 if(FT_IS_SFNT(ft_face))
6982 if (font->ntmFlags & NTM_PS_OPENTYPE)
6983 TM.tmPitchAndFamily |= TMPF_DEVICE;
6985 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6988 TM.tmCharSet = font->charset;
6990 font->potm->otmFiller = 0;
6991 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6992 font->potm->otmfsSelection = pOS2->fsSelection;
6993 font->potm->otmfsType = pOS2->fsType;
6994 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6995 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6996 font->potm->otmItalicAngle = 0; /* POST table */
6997 font->potm->otmEMSquare = ft_face->units_per_EM;
6998 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6999 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
7000 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
7001 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
7002 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
7003 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
7004 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
7005 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
7006 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
7007 font->potm->otmMacAscent = TM.tmAscent;
7008 font->potm->otmMacDescent = -TM.tmDescent;
7009 font->potm->otmMacLineGap = font->potm->otmLineGap;
7010 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7011 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
7012 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
7013 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
7014 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
7015 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
7016 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
7017 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
7018 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
7019 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
7020 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
7022 font->potm->otmsUnderscoreSize = 0;
7023 font->potm->otmsUnderscorePosition = 0;
7025 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
7026 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
7030 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7031 cp = (char*)font->potm + sizeof(*font->potm);
7032 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7033 strcpyW((WCHAR*)cp, family_nameW);
7035 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7036 strcpyW((WCHAR*)cp, style_nameW);
7038 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7039 strcpyW((WCHAR*)cp, face_nameW);
7041 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7042 strcpyW((WCHAR*)cp, full_nameW);
7046 HeapFree(GetProcessHeap(), 0, style_nameW);
7047 HeapFree(GetProcessHeap(), 0, family_nameW);
7048 HeapFree(GetProcessHeap(), 0, face_nameW);
7049 HeapFree(GetProcessHeap(), 0, full_nameW);
7053 /*************************************************************
7054 * freetype_GetGlyphOutline
7056 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7057 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7059 struct freetype_physdev *physdev = get_freetype_dev( dev );
7064 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7065 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7069 EnterCriticalSection( &freetype_cs );
7070 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
7071 LeaveCriticalSection( &freetype_cs );
7075 /*************************************************************
7076 * freetype_GetTextMetrics
7078 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7080 struct freetype_physdev *physdev = get_freetype_dev( dev );
7085 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7086 return dev->funcs->pGetTextMetrics( dev, metrics );
7090 EnterCriticalSection( &freetype_cs );
7091 ret = get_text_metrics( physdev->font, metrics );
7092 LeaveCriticalSection( &freetype_cs );
7096 /*************************************************************
7097 * freetype_GetOutlineTextMetrics
7099 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7101 struct freetype_physdev *physdev = get_freetype_dev( dev );
7106 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7107 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7110 TRACE("font=%p\n", physdev->font);
7112 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7115 EnterCriticalSection( &freetype_cs );
7117 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7119 if(cbSize >= physdev->font->potm->otmSize)
7121 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7122 scale_outline_font_metrics(physdev->font, potm);
7124 ret = physdev->font->potm->otmSize;
7126 LeaveCriticalSection( &freetype_cs );
7130 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7132 HFONTLIST *hfontlist;
7133 child->font = alloc_font();
7134 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7135 if(!child->font->ft_face)
7137 free_font(child->font);
7142 child->font->font_desc = font->font_desc;
7143 child->font->ntmFlags = child->face->ntmFlags;
7144 child->font->orientation = font->orientation;
7145 child->font->scale_y = font->scale_y;
7146 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
7147 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
7148 child->font->name = strdupW(child->face->family->FamilyName);
7149 list_add_head(&child->font->hfontlist, &hfontlist->entry);
7150 child->font->base_font = font;
7151 list_add_head(&child_font_list, &child->font->entry);
7152 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
7156 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7159 CHILD_FONT *child_font;
7162 font = font->base_font;
7164 *linked_font = font;
7166 if((*glyph = get_glyph_index(font, c)))
7168 *glyph = get_GSUB_vert_glyph(font, *glyph);
7172 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7174 if(!child_font->font)
7175 if(!load_child_font(font, child_font))
7178 if(!child_font->font->ft_face)
7180 g = get_glyph_index(child_font->font, c);
7181 g = get_GSUB_vert_glyph(child_font->font, g);
7185 *linked_font = child_font->font;
7192 /*************************************************************
7193 * freetype_GetCharWidth
7195 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7197 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7200 FT_UInt glyph_index;
7201 GdiFont *linked_font;
7202 struct freetype_physdev *physdev = get_freetype_dev( dev );
7206 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7207 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7210 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7213 EnterCriticalSection( &freetype_cs );
7214 for(c = firstChar; c <= lastChar; c++) {
7215 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7216 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7217 &gm, 0, NULL, &identity);
7218 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
7220 LeaveCriticalSection( &freetype_cs );
7224 /*************************************************************
7225 * freetype_GetCharABCWidths
7227 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7229 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7232 FT_UInt glyph_index;
7233 GdiFont *linked_font;
7234 struct freetype_physdev *physdev = get_freetype_dev( dev );
7238 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7239 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7242 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7245 EnterCriticalSection( &freetype_cs );
7247 for(c = firstChar; c <= lastChar; c++) {
7248 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7249 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7250 &gm, 0, NULL, &identity);
7251 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
7252 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
7253 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
7254 FONT_GM(linked_font,glyph_index)->bbx;
7256 LeaveCriticalSection( &freetype_cs );
7260 /*************************************************************
7261 * freetype_GetCharABCWidthsI
7263 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7265 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7268 FT_UInt glyph_index;
7269 GdiFont *linked_font;
7270 struct freetype_physdev *physdev = get_freetype_dev( dev );
7274 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7275 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7278 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7282 EnterCriticalSection( &freetype_cs );
7284 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
7286 for(c = firstChar; c < firstChar+count; c++) {
7287 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
7288 &gm, 0, NULL, &identity);
7289 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
7290 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
7291 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
7292 - FONT_GM(linked_font,c)->bbx;
7295 for(c = 0; c < count; c++) {
7296 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
7297 &gm, 0, NULL, &identity);
7298 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
7299 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
7300 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
7301 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
7304 LeaveCriticalSection( &freetype_cs );
7308 /*************************************************************
7309 * freetype_GetTextExtentExPoint
7311 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7312 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7314 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7319 FT_UInt glyph_index;
7320 GdiFont *linked_font;
7321 struct freetype_physdev *physdev = get_freetype_dev( dev );
7325 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7326 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7329 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7332 EnterCriticalSection( &freetype_cs );
7335 get_text_metrics( physdev->font, &tm );
7336 size->cy = tm.tmHeight;
7338 for(idx = 0; idx < count; idx++) {
7339 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7340 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7341 &gm, 0, NULL, &identity);
7342 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7344 if (! pnfit || ext <= max_ext) {
7354 LeaveCriticalSection( &freetype_cs );
7355 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7359 /*************************************************************
7360 * freetype_GetTextExtentExPointI
7362 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7363 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7365 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7370 struct freetype_physdev *physdev = get_freetype_dev( dev );
7374 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7375 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7378 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7381 EnterCriticalSection( &freetype_cs );
7384 get_text_metrics(physdev->font, &tm);
7385 size->cy = tm.tmHeight;
7387 for(idx = 0; idx < count; idx++) {
7388 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7389 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7391 if (! pnfit || ext <= max_ext) {
7401 LeaveCriticalSection( &freetype_cs );
7402 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7406 /*************************************************************
7407 * freetype_GetFontData
7409 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7411 struct freetype_physdev *physdev = get_freetype_dev( dev );
7415 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7416 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7419 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7420 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7421 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7423 return get_font_data( physdev->font, table, offset, buf, cbData );
7426 /*************************************************************
7427 * freetype_GetTextFace
7429 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7432 struct freetype_physdev *physdev = get_freetype_dev( dev );
7436 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7437 return dev->funcs->pGetTextFace( dev, count, str );
7440 n = strlenW(physdev->font->name) + 1;
7443 lstrcpynW(str, physdev->font->name, count);
7449 /*************************************************************
7450 * freetype_GetTextCharsetInfo
7452 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7454 struct freetype_physdev *physdev = get_freetype_dev( dev );
7458 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7459 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7461 if (fs) *fs = physdev->font->fs;
7462 return physdev->font->charset;
7465 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7467 GdiFont *font = dc->gdiFont, *linked_font;
7468 struct list *first_hfont;
7472 EnterCriticalSection( &freetype_cs );
7473 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7474 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7475 if(font == linked_font)
7476 *new_hfont = dc->hFont;
7479 first_hfont = list_head(&linked_font->hfontlist);
7480 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7482 LeaveCriticalSection( &freetype_cs );
7486 /* Retrieve a list of supported Unicode ranges for a given font.
7487 * Can be called with NULL gs to calculate the buffer size. Returns
7488 * the number of ranges found.
7490 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7492 DWORD num_ranges = 0;
7494 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7497 FT_ULong char_code, char_code_prev;
7500 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7502 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7503 face->num_glyphs, glyph_code, char_code);
7505 if (!glyph_code) return 0;
7509 gs->ranges[0].wcLow = (USHORT)char_code;
7510 gs->ranges[0].cGlyphs = 0;
7511 gs->cGlyphsSupported = 0;
7517 if (char_code < char_code_prev)
7519 ERR("expected increasing char code from FT_Get_Next_Char\n");
7522 if (char_code - char_code_prev > 1)
7527 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7528 gs->ranges[num_ranges - 1].cGlyphs = 1;
7529 gs->cGlyphsSupported++;
7534 gs->ranges[num_ranges - 1].cGlyphs++;
7535 gs->cGlyphsSupported++;
7537 char_code_prev = char_code;
7538 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7542 FIXME("encoding %u not supported\n", face->charmap->encoding);
7547 /*************************************************************
7548 * freetype_GetFontUnicodeRanges
7550 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7552 struct freetype_physdev *physdev = get_freetype_dev( dev );
7553 DWORD size, num_ranges;
7557 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7558 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7561 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7562 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7565 glyphset->cbThis = size;
7566 glyphset->cRanges = num_ranges;
7567 glyphset->flAccel = 0;
7572 /*************************************************************
7573 * freetype_FontIsLinked
7575 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7577 struct freetype_physdev *physdev = get_freetype_dev( dev );
7582 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7583 return dev->funcs->pFontIsLinked( dev );
7587 EnterCriticalSection( &freetype_cs );
7588 ret = !list_empty(&physdev->font->child_fonts);
7589 LeaveCriticalSection( &freetype_cs );
7593 /*************************************************************************
7594 * GetRasterizerCaps (GDI32.@)
7596 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7598 lprs->nSize = sizeof(RASTERIZER_STATUS);
7599 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7600 lprs->nLanguageID = 0;
7604 /*************************************************************
7605 * freetype_GdiRealizationInfo
7607 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7609 struct freetype_physdev *physdev = get_freetype_dev( dev );
7610 realization_info_t *info = ptr;
7614 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7615 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7618 FIXME("(%p, %p): stub!\n", physdev->font, info);
7621 if(FT_IS_SCALABLE(physdev->font->ft_face))
7624 info->cache_num = physdev->font->cache_num;
7625 info->unknown2 = -1;
7629 /*************************************************************************
7630 * Kerning support for TrueType fonts
7632 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7634 struct TT_kern_table
7640 struct TT_kern_subtable
7649 USHORT horizontal : 1;
7651 USHORT cross_stream: 1;
7652 USHORT override : 1;
7653 USHORT reserved1 : 4;
7659 struct TT_format0_kern_subtable
7663 USHORT entrySelector;
7674 static DWORD parse_format0_kern_subtable(GdiFont *font,
7675 const struct TT_format0_kern_subtable *tt_f0_ks,
7676 const USHORT *glyph_to_char,
7677 KERNINGPAIR *kern_pair, DWORD cPairs)
7680 const struct TT_kern_pair *tt_kern_pair;
7682 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7684 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7686 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7687 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7688 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7690 if (!kern_pair || !cPairs)
7693 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7695 nPairs = min(nPairs, cPairs);
7697 for (i = 0; i < nPairs; i++)
7699 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7700 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7701 /* this algorithm appears to better match what Windows does */
7702 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7703 if (kern_pair->iKernAmount < 0)
7705 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7706 kern_pair->iKernAmount -= font->ppem;
7708 else if (kern_pair->iKernAmount > 0)
7710 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7711 kern_pair->iKernAmount += font->ppem;
7713 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7715 TRACE("left %u right %u value %d\n",
7716 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7720 TRACE("copied %u entries\n", nPairs);
7724 /*************************************************************
7725 * freetype_GetKerningPairs
7727 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7731 const struct TT_kern_table *tt_kern_table;
7732 const struct TT_kern_subtable *tt_kern_subtable;
7734 USHORT *glyph_to_char;
7736 struct freetype_physdev *physdev = get_freetype_dev( dev );
7738 if (!(font = physdev->font))
7740 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7741 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7745 EnterCriticalSection( &freetype_cs );
7746 if (font->total_kern_pairs != (DWORD)-1)
7748 if (cPairs && kern_pair)
7750 cPairs = min(cPairs, font->total_kern_pairs);
7751 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7753 else cPairs = font->total_kern_pairs;
7755 LeaveCriticalSection( &freetype_cs );
7759 font->total_kern_pairs = 0;
7761 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7763 if (length == GDI_ERROR)
7765 TRACE("no kerning data in the font\n");
7766 LeaveCriticalSection( &freetype_cs );
7770 buf = HeapAlloc(GetProcessHeap(), 0, length);
7773 WARN("Out of memory\n");
7774 LeaveCriticalSection( &freetype_cs );
7778 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7780 /* build a glyph index to char code map */
7781 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7784 WARN("Out of memory allocating a glyph index to char code map\n");
7785 HeapFree(GetProcessHeap(), 0, buf);
7786 LeaveCriticalSection( &freetype_cs );
7790 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7796 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7798 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7799 font->ft_face->num_glyphs, glyph_code, char_code);
7803 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7805 /* FIXME: This doesn't match what Windows does: it does some fancy
7806 * things with duplicate glyph index to char code mappings, while
7807 * we just avoid overriding existing entries.
7809 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7810 glyph_to_char[glyph_code] = (USHORT)char_code;
7812 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7819 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7820 for (n = 0; n <= 65535; n++)
7821 glyph_to_char[n] = (USHORT)n;
7824 tt_kern_table = buf;
7825 nTables = GET_BE_WORD(tt_kern_table->nTables);
7826 TRACE("version %u, nTables %u\n",
7827 GET_BE_WORD(tt_kern_table->version), nTables);
7829 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7831 for (i = 0; i < nTables; i++)
7833 struct TT_kern_subtable tt_kern_subtable_copy;
7835 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7836 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7837 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7839 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7840 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7841 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7843 /* According to the TrueType specification this is the only format
7844 * that will be properly interpreted by Windows and OS/2
7846 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7848 DWORD new_chunk, old_total = font->total_kern_pairs;
7850 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7851 glyph_to_char, NULL, 0);
7852 font->total_kern_pairs += new_chunk;
7854 if (!font->kern_pairs)
7855 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7856 font->total_kern_pairs * sizeof(*font->kern_pairs));
7858 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7859 font->total_kern_pairs * sizeof(*font->kern_pairs));
7861 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7862 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7865 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7867 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7870 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7871 HeapFree(GetProcessHeap(), 0, buf);
7873 if (cPairs && kern_pair)
7875 cPairs = min(cPairs, font->total_kern_pairs);
7876 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7878 else cPairs = font->total_kern_pairs;
7880 LeaveCriticalSection( &freetype_cs );
7884 static const struct gdi_dc_funcs freetype_funcs =
7886 NULL, /* pAbortDoc */
7887 NULL, /* pAbortPath */
7888 NULL, /* pAlphaBlend */
7889 NULL, /* pAngleArc */
7892 NULL, /* pBeginPath */
7893 NULL, /* pBlendImage */
7895 NULL, /* pCloseFigure */
7896 NULL, /* pCreateCompatibleDC */
7897 freetype_CreateDC, /* pCreateDC */
7898 freetype_DeleteDC, /* pDeleteDC */
7899 NULL, /* pDeleteObject */
7900 NULL, /* pDeviceCapabilities */
7901 NULL, /* pEllipse */
7903 NULL, /* pEndPage */
7904 NULL, /* pEndPath */
7905 freetype_EnumFonts, /* pEnumFonts */
7906 NULL, /* pEnumICMProfiles */
7907 NULL, /* pExcludeClipRect */
7908 NULL, /* pExtDeviceMode */
7909 NULL, /* pExtEscape */
7910 NULL, /* pExtFloodFill */
7911 NULL, /* pExtSelectClipRgn */
7912 NULL, /* pExtTextOut */
7913 NULL, /* pFillPath */
7914 NULL, /* pFillRgn */
7915 NULL, /* pFlattenPath */
7916 freetype_FontIsLinked, /* pFontIsLinked */
7917 NULL, /* pFrameRgn */
7918 NULL, /* pGdiComment */
7919 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7920 NULL, /* pGetBoundsRect */
7921 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7922 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7923 freetype_GetCharWidth, /* pGetCharWidth */
7924 NULL, /* pGetDeviceCaps */
7925 NULL, /* pGetDeviceGammaRamp */
7926 freetype_GetFontData, /* pGetFontData */
7927 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7928 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7929 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7930 NULL, /* pGetICMProfile */
7931 NULL, /* pGetImage */
7932 freetype_GetKerningPairs, /* pGetKerningPairs */
7933 NULL, /* pGetNearestColor */
7934 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7935 NULL, /* pGetPixel */
7936 NULL, /* pGetSystemPaletteEntries */
7937 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7938 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7939 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7940 freetype_GetTextFace, /* pGetTextFace */
7941 freetype_GetTextMetrics, /* pGetTextMetrics */
7942 NULL, /* pGradientFill */
7943 NULL, /* pIntersectClipRect */
7944 NULL, /* pInvertRgn */
7946 NULL, /* pModifyWorldTransform */
7948 NULL, /* pOffsetClipRgn */
7949 NULL, /* pOffsetViewportOrg */
7950 NULL, /* pOffsetWindowOrg */
7951 NULL, /* pPaintRgn */
7954 NULL, /* pPolyBezier */
7955 NULL, /* pPolyBezierTo */
7956 NULL, /* pPolyDraw */
7957 NULL, /* pPolyPolygon */
7958 NULL, /* pPolyPolyline */
7959 NULL, /* pPolygon */
7960 NULL, /* pPolyline */
7961 NULL, /* pPolylineTo */
7962 NULL, /* pPutImage */
7963 NULL, /* pRealizeDefaultPalette */
7964 NULL, /* pRealizePalette */
7965 NULL, /* pRectangle */
7966 NULL, /* pResetDC */
7967 NULL, /* pRestoreDC */
7968 NULL, /* pRoundRect */
7970 NULL, /* pScaleViewportExt */
7971 NULL, /* pScaleWindowExt */
7972 NULL, /* pSelectBitmap */
7973 NULL, /* pSelectBrush */
7974 NULL, /* pSelectClipPath */
7975 freetype_SelectFont, /* pSelectFont */
7976 NULL, /* pSelectPalette */
7977 NULL, /* pSelectPen */
7978 NULL, /* pSetArcDirection */
7979 NULL, /* pSetBkColor */
7980 NULL, /* pSetBkMode */
7981 NULL, /* pSetDCBrushColor */
7982 NULL, /* pSetDCPenColor */
7983 NULL, /* pSetDIBColorTable */
7984 NULL, /* pSetDIBitsToDevice */
7985 NULL, /* pSetDeviceClipping */
7986 NULL, /* pSetDeviceGammaRamp */
7987 NULL, /* pSetLayout */
7988 NULL, /* pSetMapMode */
7989 NULL, /* pSetMapperFlags */
7990 NULL, /* pSetPixel */
7991 NULL, /* pSetPolyFillMode */
7992 NULL, /* pSetROP2 */
7993 NULL, /* pSetRelAbs */
7994 NULL, /* pSetStretchBltMode */
7995 NULL, /* pSetTextAlign */
7996 NULL, /* pSetTextCharacterExtra */
7997 NULL, /* pSetTextColor */
7998 NULL, /* pSetTextJustification */
7999 NULL, /* pSetViewportExt */
8000 NULL, /* pSetViewportOrg */
8001 NULL, /* pSetWindowExt */
8002 NULL, /* pSetWindowOrg */
8003 NULL, /* pSetWorldTransform */
8004 NULL, /* pStartDoc */
8005 NULL, /* pStartPage */
8006 NULL, /* pStretchBlt */
8007 NULL, /* pStretchDIBits */
8008 NULL, /* pStrokeAndFillPath */
8009 NULL, /* pStrokePath */
8010 NULL, /* pUnrealizePalette */
8011 NULL, /* pWidenPath */
8012 NULL, /* wine_get_wgl_driver */
8013 GDI_PRIORITY_FONT_DRV /* priority */
8016 #else /* HAVE_FREETYPE */
8018 /*************************************************************************/
8020 BOOL WineEngInit(void)
8024 BOOL WineEngDestroyFontInstance(HFONT hfont)
8029 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8031 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8035 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8037 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8041 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8043 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8047 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8048 LPCWSTR font_file, LPCWSTR font_path )
8054 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
8059 /*************************************************************************
8060 * GetRasterizerCaps (GDI32.@)
8062 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8064 lprs->nSize = sizeof(RASTERIZER_STATUS);
8066 lprs->nLanguageID = 0;
8070 #endif /* HAVE_FREETYPE */