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(FcConfigGetCurrent);
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(FcPatternGetString);
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
241 FT_Short internal_leading;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
255 NEWTEXTMETRICEXW ntm;
259 typedef struct tagFace {
265 DWORD font_data_size;
269 FT_Fixed font_version;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
279 typedef struct tagFamily {
281 const WCHAR *FamilyName;
282 const WCHAR *EnglishName;
284 struct list *replacement;
289 INT adv; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST {
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping *mapping;
353 const WCHAR *font_name;
358 struct enum_charset_element {
361 WCHAR name[LF_FACESIZE];
364 struct enum_charset_list {
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 struct freetype_physdev
384 struct gdi_physdev dev;
388 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
390 return (struct freetype_physdev *)dev;
393 static const struct gdi_dc_funcs freetype_funcs;
395 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR * const SystemFontValues[] = {
422 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 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 };
428 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 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};
438 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};
439 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR *default_serif_list[] =
450 bitstream_vera_serif,
454 static const WCHAR *default_fixed_list[] =
458 bitstream_vera_sans_mono,
462 static const WCHAR *default_sans_list[] =
475 typedef struct tagFontSubst {
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
487 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
488 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
489 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
491 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
511 static struct list mappings_list = LIST_INIT( mappings_list );
513 static CRITICAL_SECTION freetype_cs;
514 static CRITICAL_SECTION_DEBUG critsect_debug =
517 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
518 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback = FALSE;
527 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
528 static BOOL get_outline_text_metrics(GdiFont *font);
529 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
531 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
547 * FIXEDFON.FON FixedSys
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
589 GSUB_ScriptRecord ScriptRecord[1];
595 } GSUB_LangSysRecord;
600 GSUB_LangSysRecord LangSysRecord[1];
604 WORD LookupOrder; /* Reserved */
605 WORD ReqFeatureIndex;
607 WORD FeatureIndex[1];
613 } GSUB_FeatureRecord;
617 GSUB_FeatureRecord FeatureRecord[1];
621 WORD FeatureParams; /* Reserved */
623 WORD LookupListIndex[1];
642 } GSUB_CoverageFormat1;
647 WORD StartCoverageIndex;
653 GSUB_RangeRecord RangeRecord[1];
654 } GSUB_CoverageFormat2;
657 WORD SubstFormat; /* = 1 */
660 } GSUB_SingleSubstFormat1;
663 WORD SubstFormat; /* = 2 */
667 }GSUB_SingleSubstFormat2;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
674 static char cached_path[MAX_PATH];
675 static const char *wine = "/Wine", *fonts = "/Fonts";
677 if(*cached_path) return cached_path;
679 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
682 WARN("can't create cached data folder\n");
685 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
688 WARN("can't create cached data path\n");
692 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
694 ERR("Could not create full path\n");
698 strcat(cached_path, wine);
700 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
702 WARN("Couldn't mkdir %s\n", cached_path);
706 strcat(cached_path, fonts);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
716 /******************************************************************
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path)
734 const char *filename;
738 unsigned int size, max_size;
741 TRACE("path %s\n", path);
743 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
746 WARN("failed to get ref\n");
750 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref = FSOpenResFile(&ref, fsRdPerm);
757 TRACE("unable to open resource fork\n");
764 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
767 CloseResFile(res_ref);
771 out_dir = find_cache_dir();
773 filename = strrchr(path, '/');
774 if(!filename) filename = path;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
785 unsigned short *num_faces_ptr, num_faces, face;
788 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
790 fond = Get1IndResource(fond_res, idx);
792 TRACE("got fond resource %d\n", idx);
795 fam_rec = *(FamRec**)fond;
796 num_faces_ptr = (unsigned short *)(fam_rec + 1);
797 num_faces = GET_BE_WORD(*num_faces_ptr);
799 assoc = (AsscEntry*)(num_faces_ptr + 1);
800 TRACE("num faces %04x\n", num_faces);
801 for(face = 0; face < num_faces; face++, assoc++)
804 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
805 unsigned short size, font_id;
808 size = GET_BE_WORD(assoc->fontSize);
809 font_id = GET_BE_WORD(assoc->fontID);
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
816 TRACE("trying to load sfnt id %04x\n", font_id);
817 sfnt = GetResource(sfnt_res, font_id);
820 TRACE("can't get sfnt resource %04x\n", font_id);
824 output = HeapAlloc(GetProcessHeap(), 0, output_len);
829 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
831 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
832 if(fd != -1 || errno == EEXIST)
836 unsigned char *sfnt_data;
839 sfnt_data = *(unsigned char**)sfnt;
840 write(fd, sfnt_data, GetHandleSize(sfnt));
844 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
847 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
849 ret.array[ret.size++] = output;
853 WARN("unable to create %s\n", output);
854 HeapFree(GetProcessHeap(), 0, output);
857 ReleaseResource(sfnt);
860 ReleaseResource(fond);
863 CloseResFile(res_ref);
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed FT_FixedFromFloat(double f)
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
889 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
893 static const struct list *get_face_list_from_family(const Family *family)
895 if (!list_empty(&family->faces))
896 return &family->faces;
898 return family->replacement;
901 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
906 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
907 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
909 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
912 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
914 const struct list *face_list;
915 if(face_name && strcmpiW(face_name, family->FamilyName))
917 face_list = get_face_list_from_family(family);
918 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
922 file = strrchr(face->file, '/');
927 if(!strcasecmp(file, file_nameA))
929 HeapFree(GetProcessHeap(), 0, file_nameA);
934 HeapFree(GetProcessHeap(), 0, file_nameA);
938 static Family *find_family_from_name(const WCHAR *name)
942 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
944 if(!strcmpiW(family->FamilyName, name))
951 static Family *find_family_from_any_name(const WCHAR *name)
955 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
957 if(!strcmpiW(family->FamilyName, name))
959 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
966 static void DumpSubstList(void)
970 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
972 if(psub->from.charset != -1 || psub->to.charset != -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
974 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
976 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
977 debugstr_w(psub->to.name));
982 static LPWSTR strdupW(LPCWSTR p)
985 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
986 ret = HeapAlloc(GetProcessHeap(), 0, len);
991 static LPSTR strdupA(LPCSTR p)
994 DWORD len = (strlen(p) + 1);
995 ret = HeapAlloc(GetProcessHeap(), 0, len);
1000 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1005 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1007 if(!strcmpiW(element->from.name, from_name) &&
1008 (element->from.charset == from_charset ||
1009 element->from.charset == -1))
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1020 FontSubst *from_exist, *to_exist;
1022 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1024 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1026 list_remove(&from_exist->entry);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1028 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1029 HeapFree(GetProcessHeap(), 0, from_exist);
1035 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1039 HeapFree(GetProcessHeap(), 0, subst->to.name);
1040 subst->to.name = strdupW(to_exist->to.name);
1043 list_add_tail(subst_list, &subst->entry);
1048 HeapFree(GetProcessHeap(), 0, subst->from.name);
1049 HeapFree(GetProcessHeap(), 0, subst->to.name);
1050 HeapFree(GetProcessHeap(), 0, subst);
1054 static WCHAR *towstr(UINT cp, const char *str)
1059 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1060 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1061 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1065 static void split_subst_info(NameCs *nc, LPSTR str)
1067 CHAR *p = strrchr(str, ',');
1071 nc->charset = strtol(p+1, NULL, 10);
1074 nc->name = towstr(CP_ACP, str);
1077 static void LoadSubstList(void)
1081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey) == ERROR_SUCCESS) {
1089 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1090 &valuelen, &datalen, NULL, NULL);
1092 valuelen++; /* returned value doesn't include room for '\0' */
1093 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1094 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1098 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1099 &dlen) == ERROR_SUCCESS) {
1100 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1102 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1103 split_subst_info(&psub->from, value);
1104 split_subst_info(&psub->to, data);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1109 psub->to.charset == DEFAULT_CHARSET) {
1110 HeapFree(GetProcessHeap(), 0, psub->to.name);
1111 HeapFree(GetProcessHeap(), 0, psub->from.name);
1112 HeapFree(GetProcessHeap(), 0, psub);
1114 add_font_subst(&font_subst_list, psub, 0);
1116 /* reset dlen and vlen */
1120 HeapFree(GetProcessHeap(), 0, data);
1121 HeapFree(GetProcessHeap(), 0, value);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1138 FT_UInt num_names, name_index;
1140 if(FT_IS_SFNT(ft_face))
1142 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1144 for(name_index = 0; name_index < num_names; name_index++)
1146 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1148 if((name.platform_id == req->platform_id) &&
1149 (name.encoding_id == req->encoding_id) &&
1150 (name.language_id == req->language_id) &&
1151 (name.name_id == req->name_id))
1153 req->string = name.string;
1154 req->string_len = name.string_len;
1161 req->string_len = 0;
1165 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1170 name.platform_id = TT_PLATFORM_MICROSOFT;
1171 name.encoding_id = TT_MS_ID_UNICODE_CS;
1172 name.language_id = language_id;
1173 name.name_id = name_id;
1175 if(get_name_table_entry(ft_face, &name))
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1181 for(i = 0; i < name.string_len / 2; i++)
1183 WORD *tmp = (WORD *)&name.string[i * 2];
1184 ret[i] = GET_BE_WORD(*tmp);
1187 TRACE("Got localised name %s\n", debugstr_w(ret));
1193 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1196 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1197 if(r != ERROR_SUCCESS) return r;
1198 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1199 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1202 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1204 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1207 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1210 DWORD num_strikes, max_strike_key_len;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1218 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1219 face->cached_enum_data = NULL;
1221 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1222 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1224 face->StyleName = strdupW(face_name);
1225 face->family = family;
1226 face->vertical = (family->FamilyName[0] == '@');
1228 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1230 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1231 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1232 face->FullName = fullName;
1235 face->FullName = NULL;
1237 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1238 reg_load_dword(hkey_face, face_italic_value, &italic);
1239 reg_load_dword(hkey_face, face_bold_value, &bold);
1240 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1241 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1243 needed = sizeof(face->fs);
1244 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1246 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1248 face->scalable = TRUE;
1249 memset(&face->size, 0, sizeof(face->size));
1253 face->scalable = FALSE;
1254 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1255 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1256 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1257 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1258 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face->size.height, face->size.width, face->size.size >> 6,
1262 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1266 if (italic) face->ntmFlags |= NTM_ITALIC;
1267 if (bold) face->ntmFlags |= NTM_BOLD;
1268 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face->fs.fsCsb[0], face->fs.fsCsb[1],
1272 face->fs.fsUsb[0], face->fs.fsUsb[1],
1273 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1275 if(!italic && !bold)
1276 list_add_head(&family->faces, &face->entry);
1278 list_add_tail(&family->faces, &face->entry);
1280 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1285 NULL, NULL, NULL, NULL);
1286 if(num_strikes != 0)
1288 WCHAR strike_name[10];
1289 DWORD strike_index = 0;
1291 needed = sizeof(strike_name) / sizeof(WCHAR);
1292 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1293 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1296 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1297 load_face(hkey_strike, face_name, family);
1298 RegCloseKey(hkey_strike);
1299 needed = sizeof(strike_name) / sizeof(WCHAR);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache)
1306 DWORD max_family_key_len, size;
1308 DWORD family_index = 0;
1312 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1313 NULL, NULL, NULL, NULL);
1314 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1316 size = max_family_key_len + 1;
1317 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1318 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1320 WCHAR *english_family = NULL;
1321 DWORD face_index = 0;
1323 DWORD max_face_key_len;
1325 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1326 TRACE("opened family key %s\n", debugstr_w(family_name));
1327 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1329 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1330 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1333 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1334 family->FamilyName = strdupW(family_name);
1335 family->EnglishName = english_family;
1336 list_init(&family->faces);
1337 family->replacement = &family->faces;
1338 list_add_tail(&font_list, &family->entry);
1342 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1343 subst->from.name = strdupW(english_family);
1344 subst->from.charset = -1;
1345 subst->to.name = strdupW(family_name);
1346 subst->to.charset = -1;
1347 add_font_subst(&font_subst_list, subst, 0);
1350 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1351 NULL, NULL, NULL, NULL);
1353 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1354 size = max_face_key_len + 1;
1355 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1356 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1360 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1361 load_face(hkey_face, face_name, family);
1362 RegCloseKey(hkey_face);
1363 size = max_face_key_len + 1;
1365 HeapFree(GetProcessHeap(), 0, face_name);
1366 RegCloseKey(hkey_family);
1367 size = max_family_key_len + 1;
1370 HeapFree(GetProcessHeap(), 0, family_name);
1373 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1376 HKEY hkey_wine_fonts;
1378 /* We don't want to create the fonts key as volatile, so open this first */
1379 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1380 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1381 if(ret != ERROR_SUCCESS)
1383 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1387 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1388 KEY_ALL_ACCESS, NULL, hkey, disposition);
1389 RegCloseKey(hkey_wine_fonts);
1393 static void add_face_to_cache(Face *face)
1395 HKEY hkey_font_cache, hkey_family, hkey_face;
1396 WCHAR *face_key_name;
1398 create_font_cache_key(&hkey_font_cache, NULL);
1400 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1401 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1402 if(face->family->EnglishName)
1403 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1404 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1407 face_key_name = face->StyleName;
1410 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1411 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1412 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1414 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1417 HeapFree(GetProcessHeap(), 0, face_key_name);
1419 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1421 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1422 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1424 reg_save_dword(hkey_face, face_index_value, face->face_index);
1425 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1426 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1427 reg_save_dword(hkey_face, face_version_value, face->font_version);
1428 reg_save_dword(hkey_face, face_external_value, face->external);
1430 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1434 reg_save_dword(hkey_face, face_height_value, face->size.height);
1435 reg_save_dword(hkey_face, face_width_value, face->size.width);
1436 reg_save_dword(hkey_face, face_size_value, face->size.size);
1437 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1438 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1439 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1441 RegCloseKey(hkey_face);
1442 RegCloseKey(hkey_family);
1443 RegCloseKey(hkey_font_cache);
1446 static inline int TestStyles(DWORD flags, DWORD styles)
1448 return (flags & styles) == styles;
1451 static int StyleOrdering(Face *face)
1453 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1455 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1457 if (TestStyles(face->ntmFlags, NTM_BOLD))
1459 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1462 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1463 debugstr_w(face->family->FamilyName),
1464 debugstr_w(face->StyleName),
1470 /* Add a style of face to a font family using an ordering of the list such
1471 that regular fonts come before bold and italic, and single styles come
1472 before compound styles. */
1473 static void AddFaceToFamily(Face *face, Family *family)
1477 LIST_FOR_EACH( entry, &family->faces )
1479 Face *ent = LIST_ENTRY(entry, Face, entry);
1480 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1482 list_add_before( entry, &face->entry );
1485 static WCHAR *prepend_at(WCHAR *family)
1492 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1494 strcpyW(str + 1, family);
1495 HeapFree(GetProcessHeap(), 0, family);
1499 #define ADDFONT_EXTERNAL_FONT 0x01
1500 #define ADDFONT_FORCE_BITMAP 0x02
1501 #define ADDFONT_ADD_TO_CACHE 0x04
1503 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size, FT_Long face_index, DWORD flags, BOOL vertical)
1512 WCHAR *english_family, *localised_family;
1514 struct list *face_elem_ptr;
1515 FT_WinFNT_HeaderRec winfnt_header;
1516 int internal_leading;
1518 My_FT_Bitmap_Size *size = NULL;
1521 if(!FT_IS_SCALABLE(ft_face))
1522 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1524 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1525 if (!english_family)
1526 english_family = towstr(CP_ACP, ft_face->family_name);
1528 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1529 if (localised_family && !strcmpiW(localised_family, english_family))
1531 HeapFree(GetProcessHeap(), 0, localised_family);
1532 localised_family = NULL;
1537 english_family = prepend_at(english_family);
1538 localised_family = prepend_at(localised_family);
1541 family = find_family_from_name(localised_family ? localised_family : english_family);
1543 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1544 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1545 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1546 list_init(&family->faces);
1547 family->replacement = &family->faces;
1548 list_add_tail(&font_list, &family->entry);
1550 if(localised_family) {
1551 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1552 subst->from.name = strdupW(english_family);
1553 subst->from.charset = -1;
1554 subst->to.name = strdupW(localised_family);
1555 subst->to.charset = -1;
1556 add_font_subst(&font_subst_list, subst, 0);
1559 HeapFree(GetProcessHeap(), 0, localised_family);
1560 HeapFree(GetProcessHeap(), 0, english_family);
1562 StyleW = towstr(CP_ACP, ft_face->style_name);
1564 internal_leading = 0;
1565 memset(&fs, 0, sizeof(fs));
1567 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1569 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1570 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1571 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1572 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1573 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1574 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1575 if(pOS2->version == 0) {
1578 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1579 fs.fsCsb[0] |= FS_LATIN1;
1581 fs.fsCsb[0] |= FS_SYMBOL;
1584 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1586 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1587 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1588 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1590 internal_leading = winfnt_header.internal_leading;
1593 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1594 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1595 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1596 if(!strcmpiW(face->StyleName, StyleW) &&
1597 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1598 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1599 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1600 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1602 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1603 TRACE("Original font is newer so skipping this one\n");
1604 HeapFree(GetProcessHeap(), 0, StyleW);
1607 TRACE("Replacing original with this one\n");
1608 list_remove(&face->entry);
1609 HeapFree(GetProcessHeap(), 0, face->file);
1610 HeapFree(GetProcessHeap(), 0, face->StyleName);
1611 HeapFree(GetProcessHeap(), 0, face->FullName);
1612 HeapFree(GetProcessHeap(), 0, face);
1617 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1618 face->cached_enum_data = NULL;
1619 face->StyleName = StyleW;
1620 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1623 face->file = strdupA(file);
1624 face->font_data_ptr = NULL;
1625 face->font_data_size = 0;
1630 face->font_data_ptr = font_data_ptr;
1631 face->font_data_size = font_data_size;
1633 face->face_index = face_index;
1635 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1636 face->ntmFlags |= NTM_ITALIC;
1637 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1638 face->ntmFlags |= NTM_BOLD;
1639 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1640 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1641 face->family = family;
1642 face->vertical = vertical;
1643 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1646 if(FT_IS_SCALABLE(ft_face)) {
1647 memset(&face->size, 0, sizeof(face->size));
1648 face->scalable = TRUE;
1650 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1651 size->height, size->width, size->size >> 6,
1652 size->x_ppem >> 6, size->y_ppem >> 6);
1653 face->size.height = size->height;
1654 face->size.width = size->width;
1655 face->size.size = size->size;
1656 face->size.x_ppem = size->x_ppem;
1657 face->size.y_ppem = size->y_ppem;
1658 face->size.internal_leading = internal_leading;
1659 face->scalable = FALSE;
1662 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1664 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1666 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1667 face->ntmFlags |= NTM_PS_OPENTYPE;
1670 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1671 face->fs.fsCsb[0], face->fs.fsCsb[1],
1672 face->fs.fsUsb[0], face->fs.fsUsb[1],
1673 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1675 if(face->fs.fsCsb[0] == 0)
1679 /* let's see if we can find any interesting cmaps */
1680 for(i = 0; i < ft_face->num_charmaps; i++) {
1681 switch(ft_face->charmaps[i]->encoding) {
1682 case FT_ENCODING_UNICODE:
1683 case FT_ENCODING_APPLE_ROMAN:
1684 face->fs.fsCsb[0] |= FS_LATIN1;
1686 case FT_ENCODING_MS_SYMBOL:
1687 face->fs.fsCsb[0] |= FS_SYMBOL;
1695 if(flags & ADDFONT_ADD_TO_CACHE)
1696 add_face_to_cache(face);
1698 AddFaceToFamily(face, family);
1700 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1702 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1703 debugstr_w(StyleW));
1706 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1711 FT_Long face_index = 0, num_faces;
1714 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1715 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1717 #ifdef HAVE_CARBON_CARBON_H
1720 char **mac_list = expand_mac_font(file);
1723 BOOL had_one = FALSE;
1725 for(cursor = mac_list; *cursor; cursor++)
1728 AddFontToList(*cursor, NULL, 0, flags);
1729 HeapFree(GetProcessHeap(), 0, *cursor);
1731 HeapFree(GetProcessHeap(), 0, mac_list);
1736 #endif /* HAVE_CARBON_CARBON_H */
1741 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1742 err = pFT_New_Face(library, file, face_index, &ft_face);
1745 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1746 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1750 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1754 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1755 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1756 pFT_Done_Face(ft_face);
1760 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1761 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1762 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1763 pFT_Done_Face(ft_face);
1767 if(FT_IS_SFNT(ft_face))
1769 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1770 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1771 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))
1773 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1774 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1775 pFT_Done_Face(ft_face);
1779 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1780 we don't want to load these. */
1781 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1785 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1787 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1788 pFT_Done_Face(ft_face);
1794 if(!ft_face->family_name || !ft_face->style_name) {
1795 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1796 pFT_Done_Face(ft_face);
1800 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1802 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1803 pFT_Done_Face(ft_face);
1807 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1810 if (FT_HAS_VERTICAL(ft_face))
1812 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1816 num_faces = ft_face->num_faces;
1817 pFT_Done_Face(ft_face);
1818 } while(num_faces > ++face_index);
1822 static void DumpFontList(void)
1826 struct list *family_elem_ptr, *face_elem_ptr;
1828 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1829 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1830 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1831 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1832 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1833 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1835 TRACE(" %d", face->size.height);
1842 /***********************************************************
1843 * The replacement list is a way to map an entire font
1844 * family onto another family. For example adding
1846 * [HKCU\Software\Wine\Fonts\Replacements]
1847 * "Wingdings"="Winedings"
1849 * would enumerate the Winedings font both as Winedings and
1850 * Wingdings. However if a real Wingdings font is present the
1851 * replacement does not take place.
1854 static void LoadReplaceList(void)
1857 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1862 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1863 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1865 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1866 &valuelen, &datalen, NULL, NULL);
1868 valuelen++; /* returned value doesn't include room for '\0' */
1869 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1870 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1874 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1875 &dlen) == ERROR_SUCCESS) {
1876 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1877 /* "NewName"="Oldname" */
1878 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1880 if(!find_family_from_any_name(value))
1882 Family * const family = find_family_from_any_name(data);
1885 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1886 if (new_family != NULL)
1888 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1889 new_family->FamilyName = strdupW(value);
1890 new_family->EnglishName = NULL;
1891 list_init(&new_family->faces);
1892 new_family->replacement = &family->faces;
1893 list_add_tail(&font_list, &new_family->entry);
1898 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1903 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1905 /* reset dlen and vlen */
1909 HeapFree(GetProcessHeap(), 0, data);
1910 HeapFree(GetProcessHeap(), 0, value);
1915 static const WCHAR *font_links_list[] =
1917 Lucida_Sans_Unicode,
1918 Microsoft_Sans_Serif,
1922 static const struct font_links_defaults_list
1924 /* Keyed off substitution for "MS Shell Dlg" */
1925 const WCHAR *shelldlg;
1926 /* Maximum of four substitutes, plus terminating NULL pointer */
1927 const WCHAR *substitutes[5];
1928 } font_links_defaults_list[] =
1930 /* Non East-Asian */
1931 { Tahoma, /* FIXME unverified ordering */
1932 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
1934 /* Below lists are courtesy of
1935 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1939 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
1941 /* Chinese Simplified */
1943 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
1947 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
1949 /* Chinese Traditional */
1951 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
1956 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
1958 SYSTEM_LINKS *font_link;
1960 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1962 if(!strcmpiW(font_link->font_name, name))
1969 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
1981 SYSTEM_LINKS *font_link;
1983 psub = get_font_subst(&font_subst_list, name, -1);
1984 /* Don't store fonts that are only substitutes for other fonts */
1987 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
1991 font_link = find_font_link(name);
1992 if (font_link == NULL)
1994 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1995 font_link->font_name = strdupW(name);
1996 list_init(&font_link->links);
1997 list_add_tail(&system_links, &font_link->entry);
2000 memset(&font_link->fs, 0, sizeof font_link->fs);
2001 for (i = 0; values[i] != NULL; i++)
2003 const struct list *face_list;
2004 CHILD_FONT *child_font;
2007 if (!strcmpiW(name,value))
2009 psub = get_font_subst(&font_subst_list, value, -1);
2011 value = psub->to.name;
2012 family = find_family_from_name(value);
2016 /* Use first extant filename for this Family */
2017 face_list = get_face_list_from_family(family);
2018 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2022 file = strrchr(face->file, '/');
2031 fileW = towstr(CP_UNIXCP, file);
2033 face = find_face_from_filename(fileW, value);
2036 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2040 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2041 child_font->face = face;
2042 child_font->font = NULL;
2043 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2044 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2045 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2046 list_add_tail(&font_link->links, &child_font->entry);
2048 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2049 HeapFree(GetProcessHeap(), 0, fileW);
2055 /*************************************************************
2058 static BOOL init_system_links(void)
2062 DWORD type, max_val, max_data, val_len, data_len, index;
2063 WCHAR *value, *data;
2064 WCHAR *entry, *next;
2065 SYSTEM_LINKS *font_link, *system_font_link;
2066 CHILD_FONT *child_font;
2067 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2068 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2069 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2074 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2076 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2077 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2078 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2079 val_len = max_val + 1;
2080 data_len = max_data;
2082 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2084 psub = get_font_subst(&font_subst_list, value, -1);
2085 /* Don't store fonts that are only substitutes for other fonts */
2088 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2091 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2092 font_link->font_name = strdupW(value);
2093 memset(&font_link->fs, 0, sizeof font_link->fs);
2094 list_init(&font_link->links);
2095 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2098 CHILD_FONT *child_font;
2100 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2102 next = entry + strlenW(entry) + 1;
2104 face_name = strchrW(entry, ',');
2108 while(isspaceW(*face_name))
2111 psub = get_font_subst(&font_subst_list, face_name, -1);
2113 face_name = psub->to.name;
2115 face = find_face_from_filename(entry, face_name);
2118 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2122 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2123 child_font->face = face;
2124 child_font->font = NULL;
2125 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2126 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2127 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2128 list_add_tail(&font_link->links, &child_font->entry);
2130 list_add_tail(&system_links, &font_link->entry);
2132 val_len = max_val + 1;
2133 data_len = max_data;
2136 HeapFree(GetProcessHeap(), 0, value);
2137 HeapFree(GetProcessHeap(), 0, data);
2142 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2144 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2148 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2150 const FontSubst *psub2;
2151 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2153 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2155 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2156 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2158 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2159 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2161 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2163 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2169 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2172 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2173 system_font_link->font_name = strdupW(System);
2174 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2175 list_init(&system_font_link->links);
2177 face = find_face_from_filename(tahoma_ttf, Tahoma);
2180 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2181 child_font->face = face;
2182 child_font->font = NULL;
2183 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2184 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2185 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2186 list_add_tail(&system_font_link->links, &child_font->entry);
2188 font_link = find_font_link(Tahoma);
2189 if (font_link != NULL)
2191 CHILD_FONT *font_link_entry;
2192 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2194 CHILD_FONT *new_child;
2195 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2196 new_child->face = font_link_entry->face;
2197 new_child->font = NULL;
2198 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2199 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2200 list_add_tail(&system_font_link->links, &new_child->entry);
2203 list_add_tail(&system_links, &system_font_link->entry);
2207 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2210 struct dirent *dent;
2211 char path[MAX_PATH];
2213 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2215 dir = opendir(dirname);
2217 WARN("Can't open directory %s\n", debugstr_a(dirname));
2220 while((dent = readdir(dir)) != NULL) {
2221 struct stat statbuf;
2223 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2226 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2228 sprintf(path, "%s/%s", dirname, dent->d_name);
2230 if(stat(path, &statbuf) == -1)
2232 WARN("Can't stat %s\n", debugstr_a(path));
2235 if(S_ISDIR(statbuf.st_mode))
2236 ReadFontDir(path, external_fonts);
2239 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2240 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2241 AddFontToList(path, NULL, 0, addfont_flags);
2248 static void load_fontconfig_fonts(void)
2250 #ifdef SONAME_LIBFONTCONFIG
2251 void *fc_handle = NULL;
2260 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2262 TRACE("Wine cannot find the fontconfig library (%s).\n",
2263 SONAME_LIBFONTCONFIG);
2266 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
2267 LOAD_FUNCPTR(FcConfigGetCurrent);
2268 LOAD_FUNCPTR(FcFontList);
2269 LOAD_FUNCPTR(FcFontSetDestroy);
2270 LOAD_FUNCPTR(FcInit);
2271 LOAD_FUNCPTR(FcObjectSetAdd);
2272 LOAD_FUNCPTR(FcObjectSetCreate);
2273 LOAD_FUNCPTR(FcObjectSetDestroy);
2274 LOAD_FUNCPTR(FcPatternCreate);
2275 LOAD_FUNCPTR(FcPatternDestroy);
2276 LOAD_FUNCPTR(FcPatternGetBool);
2277 LOAD_FUNCPTR(FcPatternGetString);
2280 if(!pFcInit()) return;
2282 config = pFcConfigGetCurrent();
2283 pat = pFcPatternCreate();
2284 os = pFcObjectSetCreate();
2285 pFcObjectSetAdd(os, FC_FILE);
2286 pFcObjectSetAdd(os, FC_SCALABLE);
2287 fontset = pFcFontList(config, pat, os);
2288 if(!fontset) return;
2289 for(i = 0; i < fontset->nfont; i++) {
2292 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2294 TRACE("fontconfig: %s\n", file);
2296 /* We're just interested in OT/TT fonts for now, so this hack just
2297 picks up the scalable fonts without extensions .pf[ab] to save time
2298 loading every other font */
2300 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2302 TRACE("not scalable\n");
2306 len = strlen( file );
2307 if(len < 4) continue;
2308 ext = &file[ len - 3 ];
2309 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2310 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2312 pFcFontSetDestroy(fontset);
2313 pFcObjectSetDestroy(os);
2314 pFcPatternDestroy(pat);
2320 static BOOL load_font_from_data_dir(LPCWSTR file)
2323 const char *data_dir = wine_get_data_dir();
2325 if (!data_dir) data_dir = wine_get_build_dir();
2332 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2334 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2336 strcpy(unix_name, data_dir);
2337 strcat(unix_name, "/fonts/");
2339 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2341 EnterCriticalSection( &freetype_cs );
2342 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2343 LeaveCriticalSection( &freetype_cs );
2344 HeapFree(GetProcessHeap(), 0, unix_name);
2349 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2351 static const WCHAR slashW[] = {'\\','\0'};
2353 WCHAR windowsdir[MAX_PATH];
2356 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2357 strcatW(windowsdir, fontsW);
2358 strcatW(windowsdir, slashW);
2359 strcatW(windowsdir, file);
2360 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2361 EnterCriticalSection( &freetype_cs );
2362 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2363 LeaveCriticalSection( &freetype_cs );
2364 HeapFree(GetProcessHeap(), 0, unixname);
2369 static void load_system_fonts(void)
2372 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2373 const WCHAR * const *value;
2375 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2378 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2379 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2380 strcatW(windowsdir, fontsW);
2381 for(value = SystemFontValues; *value; value++) {
2382 dlen = sizeof(data);
2383 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2387 sprintfW(pathW, fmtW, windowsdir, data);
2388 if((unixname = wine_get_unix_file_name(pathW))) {
2389 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2390 HeapFree(GetProcessHeap(), 0, unixname);
2393 load_font_from_data_dir(data);
2400 /*************************************************************
2402 * This adds registry entries for any externally loaded fonts
2403 * (fonts from fontconfig or FontDirs). It also deletes entries
2404 * of no longer existing fonts.
2407 static void update_reg_entries(void)
2409 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2414 struct list *family_elem_ptr, *face_elem_ptr;
2416 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2417 static const WCHAR spaceW[] = {' ', '\0'};
2420 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2421 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2422 ERR("Can't create Windows font reg key\n");
2426 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2427 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2428 ERR("Can't create Windows font reg key\n");
2432 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2433 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2434 ERR("Can't create external font reg key\n");
2438 /* enumerate the fonts and add external ones to the two keys */
2440 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2441 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2442 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2443 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2444 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2445 if(!face->external) continue;
2447 if (!(face->ntmFlags & NTM_REGULAR))
2448 len = len_fam + strlenW(face->StyleName) + 1;
2449 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2450 strcpyW(valueW, family->FamilyName);
2451 if(len != len_fam) {
2452 strcatW(valueW, spaceW);
2453 strcatW(valueW, face->StyleName);
2455 strcatW(valueW, TrueType);
2457 file = wine_get_dos_file_name(face->file);
2459 len = strlenW(file) + 1;
2462 if((path = strrchr(face->file, '/')) == NULL)
2466 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2468 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2469 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2471 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2472 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2473 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2475 HeapFree(GetProcessHeap(), 0, file);
2476 HeapFree(GetProcessHeap(), 0, valueW);
2480 if(external_key) RegCloseKey(external_key);
2481 if(win9x_key) RegCloseKey(win9x_key);
2482 if(winnt_key) RegCloseKey(winnt_key);
2486 static void delete_external_font_keys(void)
2488 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2489 DWORD dlen, vlen, datalen, valuelen, i, type;
2493 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2494 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2495 ERR("Can't create Windows font reg key\n");
2499 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2500 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2501 ERR("Can't create Windows font reg key\n");
2505 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2506 ERR("Can't create external font reg key\n");
2510 /* Delete all external fonts added last time */
2512 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2513 &valuelen, &datalen, NULL, NULL);
2514 valuelen++; /* returned value doesn't include room for '\0' */
2515 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2516 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2518 dlen = datalen * sizeof(WCHAR);
2521 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2522 &dlen) == ERROR_SUCCESS) {
2524 RegDeleteValueW(winnt_key, valueW);
2525 RegDeleteValueW(win9x_key, valueW);
2526 /* reset dlen and vlen */
2530 HeapFree(GetProcessHeap(), 0, data);
2531 HeapFree(GetProcessHeap(), 0, valueW);
2533 /* Delete the old external fonts key */
2534 RegCloseKey(external_key);
2535 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2538 if(win9x_key) RegCloseKey(win9x_key);
2539 if(winnt_key) RegCloseKey(winnt_key);
2542 /*************************************************************
2543 * WineEngAddFontResourceEx
2546 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2552 if (ft_handle) /* do it only if we have freetype up and running */
2557 FIXME("Ignoring flags %x\n", flags);
2559 if((unixname = wine_get_unix_file_name(file)))
2561 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2563 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2564 EnterCriticalSection( &freetype_cs );
2565 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2566 LeaveCriticalSection( &freetype_cs );
2567 HeapFree(GetProcessHeap(), 0, unixname);
2569 if (!ret && !strchrW(file, '\\')) {
2570 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2571 ret = load_font_from_winfonts_dir(file);
2573 /* Try in datadir/fonts (or builddir/fonts),
2574 * needed for Magic the Gathering Online
2576 ret = load_font_from_data_dir(file);
2583 /*************************************************************
2584 * WineEngAddFontMemResourceEx
2587 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2591 if (ft_handle) /* do it only if we have freetype up and running */
2593 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2595 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2596 memcpy(pFontCopy, pbFont, cbFont);
2598 EnterCriticalSection( &freetype_cs );
2599 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2600 LeaveCriticalSection( &freetype_cs );
2604 TRACE("AddFontToList failed\n");
2605 HeapFree(GetProcessHeap(), 0, pFontCopy);
2608 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2609 * For now return something unique but quite random
2611 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2612 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2619 /*************************************************************
2620 * WineEngRemoveFontResourceEx
2623 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2626 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2630 static const struct nls_update_font_list
2632 UINT ansi_cp, oem_cp;
2633 const char *oem, *fixed, *system;
2634 const char *courier, *serif, *small, *sserif;
2635 /* these are for font substitutes */
2636 const char *shelldlg, *tmsrmn;
2637 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2641 const char *from, *to;
2642 } arial_0, courier_new_0, times_new_roman_0;
2643 } nls_update_font_list[] =
2645 /* Latin 1 (United States) */
2646 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2647 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2648 "Tahoma","Times New Roman",
2649 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2652 /* Latin 1 (Multilingual) */
2653 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2654 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2655 "Tahoma","Times New Roman", /* FIXME unverified */
2656 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2659 /* Eastern Europe */
2660 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2661 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2662 "Tahoma","Times New Roman", /* FIXME unverified */
2663 "Fixedsys,238", "System,238",
2664 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2665 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2666 { "Arial CE,0", "Arial,238" },
2667 { "Courier New CE,0", "Courier New,238" },
2668 { "Times New Roman CE,0", "Times New Roman,238" }
2671 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2672 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2673 "Tahoma","Times New Roman", /* FIXME unverified */
2674 "Fixedsys,204", "System,204",
2675 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2676 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2677 { "Arial Cyr,0", "Arial,204" },
2678 { "Courier New Cyr,0", "Courier New,204" },
2679 { "Times New Roman Cyr,0", "Times New Roman,204" }
2682 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2683 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2684 "Tahoma","Times New Roman", /* FIXME unverified */
2685 "Fixedsys,161", "System,161",
2686 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2687 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2688 { "Arial Greek,0", "Arial,161" },
2689 { "Courier New Greek,0", "Courier New,161" },
2690 { "Times New Roman Greek,0", "Times New Roman,161" }
2693 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2694 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2695 "Tahoma","Times New Roman", /* FIXME unverified */
2696 "Fixedsys,162", "System,162",
2697 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2698 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2699 { "Arial Tur,0", "Arial,162" },
2700 { "Courier New Tur,0", "Courier New,162" },
2701 { "Times New Roman Tur,0", "Times New Roman,162" }
2704 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2705 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2706 "Tahoma","Times New Roman", /* FIXME unverified */
2707 "Fixedsys,177", "System,177",
2708 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2709 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2713 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2714 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2715 "Tahoma","Times New Roman", /* FIXME unverified */
2716 "Fixedsys,178", "System,178",
2717 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2718 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2722 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2723 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2724 "Tahoma","Times New Roman", /* FIXME unverified */
2725 "Fixedsys,186", "System,186",
2726 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2727 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2728 { "Arial Baltic,0", "Arial,186" },
2729 { "Courier New Baltic,0", "Courier New,186" },
2730 { "Times New Roman Baltic,0", "Times New Roman,186" }
2733 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2734 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2735 "Tahoma","Times New Roman", /* FIXME unverified */
2736 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2740 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2741 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2742 "Tahoma","Times New Roman", /* FIXME unverified */
2743 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2747 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2748 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2749 "MS UI Gothic","MS Serif",
2750 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2753 /* Chinese Simplified */
2754 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2755 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2756 "SimSun", "NSimSun",
2757 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2761 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2762 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2764 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2767 /* Chinese Traditional */
2768 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2769 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2770 "PMingLiU", "MingLiU",
2771 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2776 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2778 return ( ansi_cp == 932 /* CP932 for Japanese */
2779 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2780 || ansi_cp == 949 /* CP949 for Korean */
2781 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2784 static inline HKEY create_fonts_NT_registry_key(void)
2788 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2789 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2793 static inline HKEY create_fonts_9x_registry_key(void)
2797 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2798 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2802 static inline HKEY create_config_fonts_registry_key(void)
2806 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2807 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2811 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2813 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2814 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2815 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2816 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2819 static void set_value_key(HKEY hkey, const char *name, const char *value)
2822 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2824 RegDeleteValueA(hkey, name);
2827 static void update_font_info(void)
2829 char buf[40], cpbuf[40];
2832 UINT i, ansi_cp = 0, oem_cp = 0;
2835 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2838 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2839 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2840 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2841 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2842 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2844 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2845 if (is_dbcs_ansi_cp(ansi_cp))
2846 use_default_fallback = TRUE;
2849 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2851 if (!strcmp( buf, cpbuf )) /* already set correctly */
2856 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2858 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2860 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2863 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2867 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2868 nls_update_font_list[i].oem_cp == oem_cp)
2870 hkey = create_config_fonts_registry_key();
2871 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2872 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2873 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2876 hkey = create_fonts_NT_registry_key();
2877 add_font_list(hkey, &nls_update_font_list[i]);
2880 hkey = create_fonts_9x_registry_key();
2881 add_font_list(hkey, &nls_update_font_list[i]);
2884 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2886 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2887 strlen(nls_update_font_list[i].shelldlg)+1);
2888 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2889 strlen(nls_update_font_list[i].tmsrmn)+1);
2891 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2892 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2893 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2894 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2895 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2896 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2897 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2898 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2900 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2901 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2902 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2910 /* Delete the FontSubstitutes from other locales */
2911 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2913 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2914 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2915 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2921 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2924 static BOOL init_freetype(void)
2926 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2929 "Wine cannot find the FreeType font library. To enable Wine to\n"
2930 "use TrueType fonts please install a version of FreeType greater than\n"
2931 "or equal to 2.0.5.\n"
2932 "http://www.freetype.org\n");
2936 #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;}
2938 LOAD_FUNCPTR(FT_Done_Face)
2939 LOAD_FUNCPTR(FT_Get_Char_Index)
2940 LOAD_FUNCPTR(FT_Get_First_Char)
2941 LOAD_FUNCPTR(FT_Get_Module)
2942 LOAD_FUNCPTR(FT_Get_Next_Char)
2943 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2944 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2945 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2946 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2947 LOAD_FUNCPTR(FT_Init_FreeType)
2948 LOAD_FUNCPTR(FT_Library_Version)
2949 LOAD_FUNCPTR(FT_Load_Glyph)
2950 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2951 LOAD_FUNCPTR(FT_Matrix_Multiply)
2952 #ifndef FT_MULFIX_INLINED
2953 LOAD_FUNCPTR(FT_MulFix)
2955 LOAD_FUNCPTR(FT_New_Face)
2956 LOAD_FUNCPTR(FT_New_Memory_Face)
2957 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2958 LOAD_FUNCPTR(FT_Outline_Transform)
2959 LOAD_FUNCPTR(FT_Outline_Translate)
2960 LOAD_FUNCPTR(FT_Render_Glyph)
2961 LOAD_FUNCPTR(FT_Select_Charmap)
2962 LOAD_FUNCPTR(FT_Set_Charmap)
2963 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2964 LOAD_FUNCPTR(FT_Vector_Transform)
2965 LOAD_FUNCPTR(FT_Vector_Unit)
2967 /* Don't warn if these ones are missing */
2968 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2969 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2970 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2973 if(pFT_Init_FreeType(&library) != 0) {
2974 ERR("Can't init FreeType library\n");
2975 wine_dlclose(ft_handle, NULL, 0);
2979 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2981 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2982 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2983 ((FT_Version.minor << 8) & 0x00ff00) |
2984 ((FT_Version.patch ) & 0x0000ff);
2986 font_driver = &freetype_funcs;
2991 "Wine cannot find certain functions that it needs inside the FreeType\n"
2992 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2993 "FreeType to at least version 2.1.4.\n"
2994 "http://www.freetype.org\n");
2995 wine_dlclose(ft_handle, NULL, 0);
3000 static void init_font_list(void)
3002 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3003 static const WCHAR pathW[] = {'P','a','t','h',0};
3005 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3006 WCHAR windowsdir[MAX_PATH];
3009 const char *data_dir;
3011 delete_external_font_keys();
3013 /* load the system bitmap fonts */
3014 load_system_fonts();
3016 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3017 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3018 strcatW(windowsdir, fontsW);
3019 if((unixname = wine_get_unix_file_name(windowsdir)))
3021 ReadFontDir(unixname, FALSE);
3022 HeapFree(GetProcessHeap(), 0, unixname);
3025 /* load the system truetype fonts */
3026 data_dir = wine_get_data_dir();
3027 if (!data_dir) data_dir = wine_get_build_dir();
3028 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3030 strcpy(unixname, data_dir);
3031 strcat(unixname, "/fonts/");
3032 ReadFontDir(unixname, TRUE);
3033 HeapFree(GetProcessHeap(), 0, unixname);
3036 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3037 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3038 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3040 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3041 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3042 &hkey) == ERROR_SUCCESS)
3044 LPWSTR data, valueW;
3045 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3046 &valuelen, &datalen, NULL, NULL);
3048 valuelen++; /* returned value doesn't include room for '\0' */
3049 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3050 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3053 dlen = datalen * sizeof(WCHAR);
3055 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3056 &dlen) == ERROR_SUCCESS)
3058 if(data[0] && (data[1] == ':'))
3060 if((unixname = wine_get_unix_file_name(data)))
3062 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3063 HeapFree(GetProcessHeap(), 0, unixname);
3066 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3068 WCHAR pathW[MAX_PATH];
3069 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3072 sprintfW(pathW, fmtW, windowsdir, data);
3073 if((unixname = wine_get_unix_file_name(pathW)))
3075 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3076 HeapFree(GetProcessHeap(), 0, unixname);
3079 load_font_from_data_dir(data);
3081 /* reset dlen and vlen */
3086 HeapFree(GetProcessHeap(), 0, data);
3087 HeapFree(GetProcessHeap(), 0, valueW);
3091 load_fontconfig_fonts();
3093 /* then look in any directories that we've specified in the config file */
3094 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3095 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3101 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3103 len += sizeof(WCHAR);
3104 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3105 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3107 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3108 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3109 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3110 TRACE( "got font path %s\n", debugstr_a(valueA) );
3114 LPSTR next = strchr( ptr, ':' );
3115 if (next) *next++ = 0;
3116 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3117 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3119 strcpy( unixname, home );
3120 strcat( unixname, ptr + 1 );
3121 ReadFontDir( unixname, TRUE );
3122 HeapFree( GetProcessHeap(), 0, unixname );
3125 ReadFontDir( ptr, TRUE );
3128 HeapFree( GetProcessHeap(), 0, valueA );
3130 HeapFree( GetProcessHeap(), 0, valueW );
3136 /* Mac default font locations. */
3137 ReadFontDir( "/Library/Fonts", TRUE );
3138 ReadFontDir( "/Network/Library/Fonts", TRUE );
3139 ReadFontDir( "/System/Library/Fonts", TRUE );
3140 if ((home = getenv( "HOME" )))
3142 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3143 strcpy( unixname, home );
3144 strcat( unixname, "/Library/Fonts" );
3145 ReadFontDir( unixname, TRUE);
3146 HeapFree( GetProcessHeap(), 0, unixname );
3151 static BOOL move_to_front(const WCHAR *name)
3153 Family *family, *cursor2;
3154 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3156 if(!strcmpiW(family->FamilyName, name))
3158 list_remove(&family->entry);
3159 list_add_head(&font_list, &family->entry);
3166 static BOOL set_default(const WCHAR **name_list)
3170 if (move_to_front(*name_list)) return TRUE;
3177 static void reorder_font_list(void)
3179 set_default( default_serif_list );
3180 set_default( default_fixed_list );
3181 set_default( default_sans_list );
3184 /*************************************************************
3187 * Initialize FreeType library and create a list of available faces
3189 BOOL WineEngInit(void)
3191 HKEY hkey_font_cache;
3195 /* update locale dependent font info in registry */
3198 if(!init_freetype()) return FALSE;
3200 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3202 ERR("Failed to create font mutex\n");
3205 WaitForSingleObject(font_mutex, INFINITE);
3207 create_font_cache_key(&hkey_font_cache, &disposition);
3209 if(disposition == REG_CREATED_NEW_KEY)
3212 load_font_list_from_cache(hkey_font_cache);
3214 RegCloseKey(hkey_font_cache);
3216 reorder_font_list();
3223 if(disposition == REG_CREATED_NEW_KEY)
3224 update_reg_entries();
3226 init_system_links();
3228 ReleaseMutex(font_mutex);
3233 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3236 TT_HoriHeader *pHori;
3240 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3241 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3243 if(height == 0) height = 16;
3245 /* Calc. height of EM square:
3247 * For +ve lfHeight we have
3248 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3249 * Re-arranging gives:
3250 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3252 * For -ve lfHeight we have
3254 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3255 * with il = winAscent + winDescent - units_per_em]
3260 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3261 ppem = MulDiv(ft_face->units_per_EM, height,
3262 pHori->Ascender - pHori->Descender);
3264 ppem = MulDiv(ft_face->units_per_EM, height,
3265 pOS2->usWinAscent + pOS2->usWinDescent);
3273 static struct font_mapping *map_font_file( const char *name )
3275 struct font_mapping *mapping;
3279 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3280 if (fstat( fd, &st ) == -1) goto error;
3282 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3284 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3286 mapping->refcount++;
3291 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3294 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3297 if (mapping->data == MAP_FAILED)
3299 HeapFree( GetProcessHeap(), 0, mapping );
3302 mapping->refcount = 1;
3303 mapping->dev = st.st_dev;
3304 mapping->ino = st.st_ino;
3305 mapping->size = st.st_size;
3306 list_add_tail( &mappings_list, &mapping->entry );
3314 static void unmap_font_file( struct font_mapping *mapping )
3316 if (!--mapping->refcount)
3318 list_remove( &mapping->entry );
3319 munmap( mapping->data, mapping->size );
3320 HeapFree( GetProcessHeap(), 0, mapping );
3324 static LONG load_VDMX(GdiFont*, LONG);
3326 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3333 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3337 if (!(font->mapping = map_font_file( face->file )))
3339 WARN("failed to map %s\n", debugstr_a(face->file));
3342 data_ptr = font->mapping->data;
3343 data_size = font->mapping->size;
3347 data_ptr = face->font_data_ptr;
3348 data_size = face->font_data_size;
3351 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3353 ERR("FT_New_Face rets %d\n", err);
3357 /* set it here, as load_VDMX needs it */
3358 font->ft_face = ft_face;
3360 if(FT_IS_SCALABLE(ft_face)) {
3361 /* load the VDMX table if we have one */
3362 font->ppem = load_VDMX(font, height);
3364 font->ppem = calc_ppem_for_height(ft_face, height);
3365 TRACE("height %d => ppem %d\n", height, font->ppem);
3367 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3368 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3370 font->ppem = height;
3371 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3372 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3378 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3380 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3381 a single face with the requested charset. The idea is to check if
3382 the selected font supports the current ANSI codepage, if it does
3383 return the corresponding charset, else return the first charset */
3386 int acp = GetACP(), i;
3390 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3392 const SYSTEM_LINKS *font_link;
3394 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3395 return csi.ciCharset;
3397 font_link = find_font_link(family_name);
3398 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3399 return csi.ciCharset;
3402 for(i = 0; i < 32; i++) {
3404 if(face->fs.fsCsb[0] & fs0) {
3405 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3407 return csi.ciCharset;
3410 FIXME("TCI failing on %x\n", fs0);
3414 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3415 face->fs.fsCsb[0], face->file);
3417 return DEFAULT_CHARSET;
3420 static GdiFont *alloc_font(void)
3422 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3424 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3425 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3427 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3428 ret->total_kern_pairs = (DWORD)-1;
3429 ret->kern_pairs = NULL;
3430 list_init(&ret->hfontlist);
3431 list_init(&ret->child_fonts);
3435 static void free_font(GdiFont *font)
3437 struct list *cursor, *cursor2;
3440 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3442 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3443 list_remove(cursor);
3445 free_font(child->font);
3446 HeapFree(GetProcessHeap(), 0, child);
3449 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3451 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3452 DeleteObject(hfontlist->hfont);
3453 list_remove(&hfontlist->entry);
3454 HeapFree(GetProcessHeap(), 0, hfontlist);
3457 if (font->ft_face) pFT_Done_Face(font->ft_face);
3458 if (font->mapping) unmap_font_file( font->mapping );
3459 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3460 HeapFree(GetProcessHeap(), 0, font->potm);
3461 HeapFree(GetProcessHeap(), 0, font->name);
3462 for (i = 0; i < font->gmsize; i++)
3463 HeapFree(GetProcessHeap(),0,font->gm[i]);
3464 HeapFree(GetProcessHeap(), 0, font->gm);
3465 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3466 HeapFree(GetProcessHeap(), 0, font);
3470 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3472 FT_Face ft_face = font->ft_face;
3476 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3483 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3485 /* make sure value of len is the value freetype says it needs */
3488 FT_ULong needed = 0;
3489 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3490 if( !err && needed < len) len = needed;
3492 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3495 TRACE("Can't find table %c%c%c%c\n",
3496 /* bytes were reversed */
3497 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3498 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3504 /*************************************************************
3507 * load the vdmx entry for the specified height
3510 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3511 ( ( (FT_ULong)_x4 << 24 ) | \
3512 ( (FT_ULong)_x3 << 16 ) | \
3513 ( (FT_ULong)_x2 << 8 ) | \
3516 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3531 static LONG load_VDMX(GdiFont *font, LONG height)
3535 BYTE devXRatio, devYRatio;
3536 USHORT numRecs, numRatios;
3537 DWORD result, offset = -1;
3541 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3543 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3546 /* FIXME: need the real device aspect ratio */
3550 numRecs = GET_BE_WORD(hdr[1]);
3551 numRatios = GET_BE_WORD(hdr[2]);
3553 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3554 for(i = 0; i < numRatios; i++) {
3557 offset = (3 * 2) + (i * sizeof(Ratios));
3558 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3561 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3563 if((ratio.xRatio == 0 &&
3564 ratio.yStartRatio == 0 &&
3565 ratio.yEndRatio == 0) ||
3566 (devXRatio == ratio.xRatio &&
3567 devYRatio >= ratio.yStartRatio &&
3568 devYRatio <= ratio.yEndRatio))
3570 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3571 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3572 offset = GET_BE_WORD(tmp);
3578 FIXME("No suitable ratio found\n");
3582 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3584 BYTE startsz, endsz;
3587 recs = GET_BE_WORD(group.recs);
3588 startsz = group.startsz;
3589 endsz = group.endsz;
3591 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3593 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3594 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3595 if(result == GDI_ERROR) {
3596 FIXME("Failed to retrieve vTable\n");
3601 for(i = 0; i < recs; i++) {
3602 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3603 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3604 ppem = GET_BE_WORD(vTable[i * 3]);
3606 if(yMax + -yMin == height) {
3609 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3612 if(yMax + -yMin > height) {
3615 goto end; /* failed */
3617 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3618 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3619 ppem = GET_BE_WORD(vTable[i * 3]);
3620 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3626 TRACE("ppem not found for height %d\n", height);
3630 HeapFree(GetProcessHeap(), 0, vTable);
3636 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3638 if(font->font_desc.hash != fd->hash) return TRUE;
3639 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3640 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3641 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3642 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3645 static void calc_hash(FONT_DESC *pfd)
3647 DWORD hash = 0, *ptr, two_chars;
3651 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3653 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3655 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3657 pwc = (WCHAR *)&two_chars;
3659 *pwc = toupperW(*pwc);
3661 *pwc = toupperW(*pwc);
3665 hash ^= !pfd->can_use_bitmap;
3670 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3675 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3679 fd.can_use_bitmap = can_use_bitmap;
3682 /* try the child list */
3683 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3684 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3685 if(!fontcmp(ret, &fd)) {
3686 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3687 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3688 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3689 if(hflist->hfont == hfont)
3695 /* try the in-use list */
3696 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3697 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3698 if(!fontcmp(ret, &fd)) {
3699 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3700 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3701 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3702 if(hflist->hfont == hfont)
3705 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3706 hflist->hfont = hfont;
3707 list_add_head(&ret->hfontlist, &hflist->entry);
3712 /* then the unused list */
3713 font_elem_ptr = list_head(&unused_gdi_font_list);
3714 while(font_elem_ptr) {
3715 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3716 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3717 if(!fontcmp(ret, &fd)) {
3718 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3719 assert(list_empty(&ret->hfontlist));
3720 TRACE("Found %p in unused list\n", ret);
3721 list_remove(&ret->entry);
3722 list_add_head(&gdi_font_list, &ret->entry);
3723 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3724 hflist->hfont = hfont;
3725 list_add_head(&ret->hfontlist, &hflist->entry);
3732 static void add_to_cache(GdiFont *font)
3734 static DWORD cache_num = 1;
3736 font->cache_num = cache_num++;
3737 list_add_head(&gdi_font_list, &font->entry);
3740 /*************************************************************
3741 * create_child_font_list
3743 static BOOL create_child_font_list(GdiFont *font)
3746 SYSTEM_LINKS *font_link;
3747 CHILD_FONT *font_link_entry, *new_child;
3751 psub = get_font_subst(&font_subst_list, font->name, -1);
3752 font_name = psub ? psub->to.name : font->name;
3753 font_link = find_font_link(font_name);
3754 if (font_link != NULL)
3756 TRACE("found entry in system list\n");
3757 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3759 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3760 new_child->face = font_link_entry->face;
3761 new_child->font = NULL;
3762 list_add_tail(&font->child_fonts, &new_child->entry);
3763 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3768 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3769 * Sans Serif. This is how asian windows get default fallbacks for fonts
3771 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3772 font->charset != OEM_CHARSET &&
3773 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3775 font_link = find_font_link(szDefaultFallbackLink);
3776 if (font_link != NULL)
3778 TRACE("found entry in default fallback list\n");
3779 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3781 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3782 new_child->face = font_link_entry->face;
3783 new_child->font = NULL;
3784 list_add_tail(&font->child_fonts, &new_child->entry);
3785 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3794 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3796 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3798 if (pFT_Set_Charmap)
3801 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3803 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3805 for (i = 0; i < ft_face->num_charmaps; i++)
3807 if (ft_face->charmaps[i]->encoding == encoding)
3809 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3810 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3812 switch (ft_face->charmaps[i]->platform_id)
3815 cmap_def = ft_face->charmaps[i];
3817 case 0: /* Apple Unicode */
3818 cmap0 = ft_face->charmaps[i];
3820 case 1: /* Macintosh */
3821 cmap1 = ft_face->charmaps[i];
3824 cmap2 = ft_face->charmaps[i];
3826 case 3: /* Microsoft */
3827 cmap3 = ft_face->charmaps[i];
3832 if (cmap3) /* prefer Microsoft cmap table */
3833 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3835 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3837 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3839 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3841 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3843 return ft_err == FT_Err_Ok;
3846 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3850 /*************************************************************
3853 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3854 LPCWSTR output, const DEVMODEW *devmode )
3856 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3858 if (!physdev) return FALSE;
3859 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3864 /*************************************************************
3867 static BOOL freetype_DeleteDC( PHYSDEV dev )
3869 struct freetype_physdev *physdev = get_freetype_dev( dev );
3870 HeapFree( GetProcessHeap(), 0, physdev );
3875 /*************************************************************
3876 * freetype_SelectFont
3878 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3880 struct freetype_physdev *physdev = get_freetype_dev( dev );
3882 Face *face, *best, *best_bitmap;
3883 Family *family, *last_resort_family;
3884 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
3885 INT height, width = 0;
3886 unsigned int score = 0, new_score;
3887 signed int diff = 0, newdiff;
3888 BOOL bd, it, can_use_bitmap, want_vertical;
3893 FontSubst *psub = NULL;
3894 DC *dc = get_dc_ptr( dev->hdc );
3895 const SYSTEM_LINKS *font_link;
3897 if (!hfont) /* notification that the font has been changed by another driver */
3900 physdev->font = NULL;
3901 release_dc_ptr( dc );
3905 GetObjectW( hfont, sizeof(lf), &lf );
3906 lf.lfWidth = abs(lf.lfWidth);
3908 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3910 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3911 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3912 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3915 if(dc->GraphicsMode == GM_ADVANCED)
3917 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3918 /* Try to avoid not necessary glyph transformations */
3919 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3921 lf.lfHeight *= fabs(dcmat.eM11);
3922 lf.lfWidth *= fabs(dcmat.eM11);
3923 dcmat.eM11 = dcmat.eM22 = 1.0;
3928 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3929 font scaling abilities. */
3930 dcmat.eM11 = dcmat.eM22 = 1.0;
3931 dcmat.eM21 = dcmat.eM12 = 0;
3932 if (dc->vport2WorldValid)
3934 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3935 lf.lfOrientation = -lf.lfOrientation;
3936 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3937 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3941 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3942 dcmat.eM21, dcmat.eM22);
3945 EnterCriticalSection( &freetype_cs );
3947 /* check the cache first */
3948 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3949 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3953 if(list_empty(&font_list)) /* No fonts installed */
3955 TRACE("No fonts installed\n");
3959 TRACE("not in cache\n");
3962 ret->font_desc.matrix = dcmat;
3963 ret->font_desc.lf = lf;
3964 ret->font_desc.can_use_bitmap = can_use_bitmap;
3965 calc_hash(&ret->font_desc);
3966 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3967 hflist->hfont = hfont;
3968 list_add_head(&ret->hfontlist, &hflist->entry);
3970 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3971 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3972 original value lfCharSet. Note this is a special case for
3973 Symbol and doesn't happen at least for "Wingdings*" */
3975 if(!strcmpiW(lf.lfFaceName, SymbolW))
3976 lf.lfCharSet = SYMBOL_CHARSET;
3978 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3979 switch(lf.lfCharSet) {
3980 case DEFAULT_CHARSET:
3981 csi.fs.fsCsb[0] = 0;
3984 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3985 csi.fs.fsCsb[0] = 0;
3991 if(lf.lfFaceName[0] != '\0') {
3992 CHILD_FONT *font_link_entry;
3993 LPWSTR FaceName = lf.lfFaceName;
3995 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3998 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3999 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4000 if (psub->to.charset != -1)
4001 lf.lfCharSet = psub->to.charset;
4004 /* We want a match on name and charset or just name if
4005 charset was DEFAULT_CHARSET. If the latter then
4006 we fixup the returned charset later in get_nearest_charset
4007 where we'll either use the charset of the current ansi codepage
4008 or if that's unavailable the first charset that the font supports.
4010 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4011 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4012 if (!strcmpiW(family->FamilyName, FaceName) ||
4013 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4015 font_link = find_font_link(family->FamilyName);
4016 face_list = get_face_list_from_family(family);
4017 LIST_FOR_EACH(face_elem_ptr, face_list) {
4018 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4019 if (!(face->scalable || can_use_bitmap))
4021 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4023 if (font_link != NULL &&
4024 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4026 if (!csi.fs.fsCsb[0])
4032 /* Search by full face name. */
4033 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4034 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4035 face_list = get_face_list_from_family(family);
4036 LIST_FOR_EACH(face_elem_ptr, face_list) {
4037 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4038 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4039 (face->scalable || can_use_bitmap))
4041 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4043 font_link = find_font_link(family->FamilyName);
4044 if (font_link != NULL &&
4045 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4052 * Try check the SystemLink list first for a replacement font.
4053 * We may find good replacements there.
4055 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4057 if(!strcmpiW(font_link->font_name, FaceName) ||
4058 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4060 TRACE("found entry in system list\n");
4061 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4063 const SYSTEM_LINKS *links;
4065 face = font_link_entry->face;
4066 if (!(face->scalable || can_use_bitmap))
4068 family = face->family;
4069 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4071 links = find_font_link(family->FamilyName);
4072 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4079 psub = NULL; /* substitution is no more relevant */
4081 /* If requested charset was DEFAULT_CHARSET then try using charset
4082 corresponding to the current ansi codepage */
4083 if (!csi.fs.fsCsb[0])
4086 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4087 FIXME("TCI failed on codepage %d\n", acp);
4088 csi.fs.fsCsb[0] = 0;
4090 lf.lfCharSet = csi.ciCharset;
4093 want_vertical = (lf.lfFaceName[0] == '@');
4095 /* Face families are in the top 4 bits of lfPitchAndFamily,
4096 so mask with 0xF0 before testing */
4098 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4099 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4100 strcpyW(lf.lfFaceName, defFixed);
4101 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4102 strcpyW(lf.lfFaceName, defSerif);
4103 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4104 strcpyW(lf.lfFaceName, defSans);
4106 strcpyW(lf.lfFaceName, defSans);
4107 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4108 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4109 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4110 font_link = find_font_link(family->FamilyName);
4111 face_list = get_face_list_from_family(family);
4112 LIST_FOR_EACH(face_elem_ptr, face_list) {
4113 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4114 if (!(face->scalable || can_use_bitmap))
4116 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4118 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4124 last_resort_family = NULL;
4125 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4126 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4127 font_link = find_font_link(family->FamilyName);
4128 face_list = get_face_list_from_family(family);
4129 LIST_FOR_EACH(face_elem_ptr, face_list) {
4130 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4131 if(face->vertical == want_vertical &&
4132 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4133 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4136 if(can_use_bitmap && !last_resort_family)
4137 last_resort_family = family;
4142 if(last_resort_family) {
4143 family = last_resort_family;
4144 csi.fs.fsCsb[0] = 0;
4148 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4149 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4150 face_list = get_face_list_from_family(family);
4151 LIST_FOR_EACH(face_elem_ptr, face_list) {
4152 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4153 if(face->scalable && face->vertical == want_vertical) {
4154 csi.fs.fsCsb[0] = 0;
4155 WARN("just using first face for now\n");
4158 if(can_use_bitmap && !last_resort_family)
4159 last_resort_family = family;
4162 if(!last_resort_family) {
4163 FIXME("can't find a single appropriate font - bailing\n");
4169 WARN("could only find a bitmap font - this will probably look awful!\n");
4170 family = last_resort_family;
4171 csi.fs.fsCsb[0] = 0;
4174 it = lf.lfItalic ? 1 : 0;
4175 bd = lf.lfWeight > 550 ? 1 : 0;
4177 height = lf.lfHeight;
4179 face = best = best_bitmap = NULL;
4180 font_link = find_font_link(family->FamilyName);
4181 face_list = get_face_list_from_family(family);
4182 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4184 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4185 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4190 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4191 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4192 new_score = (italic ^ it) + (bold ^ bd);
4193 if(!best || new_score <= score)
4195 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4196 italic, bold, it, bd);
4199 if(best->scalable && score == 0) break;
4203 newdiff = height - (signed int)(best->size.height);
4205 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4206 if(!best_bitmap || new_score < score ||
4207 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4209 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4212 if(score == 0 && diff == 0) break;
4219 face = best->scalable ? best : best_bitmap;
4220 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4221 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4224 height = lf.lfHeight;
4228 if(csi.fs.fsCsb[0]) {
4229 ret->charset = lf.lfCharSet;
4230 ret->codepage = csi.ciACP;
4233 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4235 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4236 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4238 ret->aveWidth = height ? lf.lfWidth : 0;
4240 if(!face->scalable) {
4241 /* Windows uses integer scaling factors for bitmap fonts */
4242 INT scale, scaled_height;
4243 GdiFont *cachedfont;
4245 /* FIXME: rotation of bitmap fonts is ignored */
4246 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4248 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4249 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4250 dcmat.eM11 = dcmat.eM22 = 1.0;
4251 /* As we changed the matrix, we need to search the cache for the font again,
4252 * otherwise we might explode the cache. */
4253 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4254 TRACE("Found cached font after non-scalable matrix rescale!\n");
4259 calc_hash(&ret->font_desc);
4261 if (height != 0) height = diff;
4262 height += face->size.height;
4264 scale = (height + face->size.height - 1) / face->size.height;
4265 scaled_height = scale * face->size.height;
4266 /* Only jump to the next height if the difference <= 25% original height */
4267 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4268 /* The jump between unscaled and doubled is delayed by 1 */
4269 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4270 ret->scale_y = scale;
4272 width = face->size.x_ppem >> 6;
4273 height = face->size.y_ppem >> 6;
4277 TRACE("font scale y: %f\n", ret->scale_y);
4279 ret->ft_face = OpenFontFace(ret, face, width, height);
4288 ret->ntmFlags = face->ntmFlags;
4290 if (ret->charset == SYMBOL_CHARSET &&
4291 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4294 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4298 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4301 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4302 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4303 ret->underline = lf.lfUnderline ? 0xff : 0;
4304 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4305 create_child_font_list(ret);
4307 if (face->vertical) /* We need to try to load the GSUB table */
4309 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4310 if (length != GDI_ERROR)
4312 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4313 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4314 TRACE("Loaded GSUB table of %i bytes\n",length);
4318 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4325 physdev->font = ret;
4327 LeaveCriticalSection( &freetype_cs );
4328 release_dc_ptr( dc );
4329 return ret ? hfont : 0;
4332 static void dump_gdi_font_list(void)
4335 struct list *elem_ptr;
4337 TRACE("---------- gdiFont Cache ----------\n");
4338 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4339 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4340 TRACE("gdiFont=%p %s %d\n",
4341 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4344 TRACE("---------- Unused gdiFont Cache ----------\n");
4345 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4346 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4347 TRACE("gdiFont=%p %s %d\n",
4348 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4351 TRACE("---------- Child gdiFont Cache ----------\n");
4352 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4353 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4354 TRACE("gdiFont=%p %s %d\n",
4355 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4359 /*************************************************************
4360 * WineEngDestroyFontInstance
4362 * free the gdiFont associated with this handle
4365 BOOL WineEngDestroyFontInstance(HFONT handle)
4370 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4374 EnterCriticalSection( &freetype_cs );
4376 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4378 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4379 while(hfontlist_elem_ptr) {
4380 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4381 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4382 if(hflist->hfont == handle) {
4383 TRACE("removing child font %p from child list\n", gdiFont);
4384 list_remove(&gdiFont->entry);
4385 LeaveCriticalSection( &freetype_cs );
4391 TRACE("destroying hfont=%p\n", handle);
4393 dump_gdi_font_list();
4395 font_elem_ptr = list_head(&gdi_font_list);
4396 while(font_elem_ptr) {
4397 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4398 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4400 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4401 while(hfontlist_elem_ptr) {
4402 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4403 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4404 if(hflist->hfont == handle) {
4405 list_remove(&hflist->entry);
4406 HeapFree(GetProcessHeap(), 0, hflist);
4410 if(list_empty(&gdiFont->hfontlist)) {
4411 TRACE("Moving to Unused list\n");
4412 list_remove(&gdiFont->entry);
4413 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4418 font_elem_ptr = list_head(&unused_gdi_font_list);
4419 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4420 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4421 while(font_elem_ptr) {
4422 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4423 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4424 TRACE("freeing %p\n", gdiFont);
4425 list_remove(&gdiFont->entry);
4428 LeaveCriticalSection( &freetype_cs );
4432 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4439 id += IDS_FIRST_SCRIPT;
4440 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4441 if (!rsrc) return 0;
4442 hMem = LoadResource( gdi32_module, rsrc );
4443 if (!hMem) return 0;
4445 p = LockResource( hMem );
4447 while (id--) p += *p + 1;
4449 i = min(LF_FACESIZE - 1, *p);
4450 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4456 /***************************************************
4457 * create_enum_charset_list
4459 * This function creates charset enumeration list because in DEFAULT_CHARSET
4460 * case, the ANSI codepage's charset takes precedence over other charsets.
4461 * This function works as a filter other than DEFAULT_CHARSET case.
4463 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4468 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4469 csi.fs.fsCsb[0] != 0) {
4470 list->element[n].mask = csi.fs.fsCsb[0];
4471 list->element[n].charset = csi.ciCharset;
4472 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4475 else { /* charset is DEFAULT_CHARSET or invalid. */
4478 /* Set the current codepage's charset as the first element. */
4480 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4481 csi.fs.fsCsb[0] != 0) {
4482 list->element[n].mask = csi.fs.fsCsb[0];
4483 list->element[n].charset = csi.ciCharset;
4484 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4488 /* Fill out left elements. */
4489 for (i = 0; i < 32; i++) {
4491 fs.fsCsb[0] = 1L << i;
4493 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4494 continue; /* skip, already added. */
4495 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4496 continue; /* skip, this is an invalid fsCsb bit. */
4498 list->element[n].mask = fs.fsCsb[0];
4499 list->element[n].charset = csi.ciCharset;
4500 load_script_name( i, list->element[n].name );
4509 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4510 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4515 if (face->cached_enum_data)
4518 *pelf = face->cached_enum_data->elf;
4519 *pntm = face->cached_enum_data->ntm;
4520 *ptype = face->cached_enum_data->type;
4524 font = alloc_font();
4526 if(face->scalable) {
4527 height = -2048; /* 2048 is the most common em size */
4530 height = face->size.y_ppem >> 6;
4531 width = face->size.x_ppem >> 6;
4533 font->scale_y = 1.0;
4535 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4541 font->name = strdupW(face->family->FamilyName);
4542 font->ntmFlags = face->ntmFlags;
4544 if (get_outline_text_metrics(font))
4546 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4548 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4550 lstrcpynW(pelf->elfLogFont.lfFaceName,
4551 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4553 lstrcpynW(pelf->elfFullName,
4554 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4556 lstrcpynW(pelf->elfStyle,
4557 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4562 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4564 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4566 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4568 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4570 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4571 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4574 pntm->ntmTm.ntmFlags = face->ntmFlags;
4575 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4576 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4577 pntm->ntmFontSig = face->fs;
4579 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4581 pelf->elfLogFont.lfEscapement = 0;
4582 pelf->elfLogFont.lfOrientation = 0;
4583 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4584 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4585 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4586 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4587 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4588 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4589 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4590 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4591 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4592 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4593 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4596 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4597 *ptype |= TRUETYPE_FONTTYPE;
4598 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4599 *ptype |= DEVICE_FONTTYPE;
4600 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4601 *ptype |= RASTER_FONTTYPE;
4603 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4604 if (face->cached_enum_data)
4606 face->cached_enum_data->elf = *pelf;
4607 face->cached_enum_data->ntm = *pntm;
4608 face->cached_enum_data->type = *ptype;
4614 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
4616 static const WCHAR spaceW[] = { ' ', 0 };
4618 strcpyW(full_name, family_name);
4619 strcatW(full_name, spaceW);
4620 strcatW(full_name, style_name);
4623 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4625 const struct list *face_list, *face_elem_ptr;
4627 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4629 face_list = get_face_list_from_family(family);
4630 LIST_FOR_EACH(face_elem_ptr, face_list)
4632 WCHAR full_family_name[LF_FULLFACESIZE];
4633 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4635 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4637 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4638 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4642 create_full_name(full_family_name, family->FamilyName, face->StyleName);
4643 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4649 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
4651 WCHAR full_family_name[LF_FULLFACESIZE];
4653 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
4655 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4657 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4658 debugstr_w(family_name), debugstr_w(face->StyleName));
4662 create_full_name(full_family_name, family_name, face->StyleName);
4663 return !strcmpiW(lf->lfFaceName, full_family_name);
4666 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
4667 FONTENUMPROCW proc, LPARAM lparam)
4670 NEWTEXTMETRICEXW ntm;
4674 GetEnumStructs(face, &elf, &ntm, &type);
4675 for(i = 0; i < list->total; i++) {
4676 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4677 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4678 load_script_name( IDS_OEM_DOS, elf.elfScript );
4679 i = list->total; /* break out of loop after enumeration */
4680 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4683 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4684 strcpyW(elf.elfScript, list->element[i].name);
4685 if (!elf.elfScript[0])
4686 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4688 /* Font Replacement */
4689 if (family != face->family)
4691 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
4692 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
4694 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4695 debugstr_w(elf.elfLogFont.lfFaceName),
4696 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4697 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4698 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4699 ntm.ntmTm.ntmFlags);
4700 /* release section before callback (FIXME) */
4701 LeaveCriticalSection( &freetype_cs );
4702 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4703 EnterCriticalSection( &freetype_cs );
4708 /*************************************************************
4709 * freetype_EnumFonts
4711 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4715 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4717 struct enum_charset_list enum_charsets;
4721 lf.lfCharSet = DEFAULT_CHARSET;
4722 lf.lfPitchAndFamily = 0;
4723 lf.lfFaceName[0] = 0;
4727 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4729 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4732 EnterCriticalSection( &freetype_cs );
4733 if(plf->lfFaceName[0]) {
4735 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4738 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4739 debugstr_w(psub->to.name));
4741 strcpyW(lf.lfFaceName, psub->to.name);
4745 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4746 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4747 if(family_matches(family, plf)) {
4748 face_list = get_face_list_from_family(family);
4749 LIST_FOR_EACH(face_elem_ptr, face_list) {
4750 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4751 if (!face_matches(family->FamilyName, face, plf)) continue;
4752 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4757 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4758 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4759 face_list = get_face_list_from_family(family);
4760 face_elem_ptr = list_head(face_list);
4761 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4762 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4765 LeaveCriticalSection( &freetype_cs );
4769 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4771 pt->x.value = vec->x >> 6;
4772 pt->x.fract = (vec->x & 0x3f) << 10;
4773 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4774 pt->y.value = vec->y >> 6;
4775 pt->y.fract = (vec->y & 0x3f) << 10;
4776 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4780 /***************************************************
4781 * According to the MSDN documentation on WideCharToMultiByte,
4782 * certain codepages cannot set the default_used parameter.
4783 * This returns TRUE if the codepage can set that parameter, false else
4784 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4786 static BOOL codepage_sets_default_used(UINT codepage)
4800 * GSUB Table handling functions
4803 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4805 const GSUB_CoverageFormat1* cf1;
4809 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4811 int count = GET_BE_WORD(cf1->GlyphCount);
4813 TRACE("Coverage Format 1, %i glyphs\n",count);
4814 for (i = 0; i < count; i++)
4815 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4819 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4821 const GSUB_CoverageFormat2* cf2;
4824 cf2 = (const GSUB_CoverageFormat2*)cf1;
4826 count = GET_BE_WORD(cf2->RangeCount);
4827 TRACE("Coverage Format 2, %i ranges\n",count);
4828 for (i = 0; i < count; i++)
4830 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4832 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4833 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4835 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4836 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4842 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4847 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4849 const GSUB_ScriptList *script;
4850 const GSUB_Script *deflt = NULL;
4852 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4854 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4855 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4857 const GSUB_Script *scr;
4860 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4861 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4863 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4865 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4871 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4875 const GSUB_LangSys *Lang;
4877 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4879 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4881 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4882 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4884 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4887 offset = GET_BE_WORD(script->DefaultLangSys);
4890 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4896 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4899 const GSUB_FeatureList *feature;
4900 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4902 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4903 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4905 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4906 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4908 const GSUB_Feature *feat;
4909 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4916 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4920 const GSUB_LookupList *lookup;
4921 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4923 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4924 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4926 const GSUB_LookupTable *look;
4927 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4928 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4929 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4930 if (GET_BE_WORD(look->LookupType) != 1)
4931 FIXME("We only handle SubType 1\n");
4936 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4938 const GSUB_SingleSubstFormat1 *ssf1;
4939 offset = GET_BE_WORD(look->SubTable[j]);
4940 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4941 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4943 int offset = GET_BE_WORD(ssf1->Coverage);
4944 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4945 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4947 TRACE(" Glyph 0x%x ->",glyph);
4948 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4949 TRACE(" 0x%x\n",glyph);
4954 const GSUB_SingleSubstFormat2 *ssf2;
4958 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4959 offset = GET_BE_WORD(ssf1->Coverage);
4960 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4961 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4962 TRACE(" Coverage index %i\n",index);
4965 TRACE(" Glyph is 0x%x ->",glyph);
4966 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4967 TRACE("0x%x\n",glyph);
4976 static const char* get_opentype_script(const GdiFont *font)
4979 * I am not sure if this is the correct way to generate our script tag
4982 switch (font->charset)
4984 case ANSI_CHARSET: return "latn";
4985 case BALTIC_CHARSET: return "latn"; /* ?? */
4986 case CHINESEBIG5_CHARSET: return "hani";
4987 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4988 case GB2312_CHARSET: return "hani";
4989 case GREEK_CHARSET: return "grek";
4990 case HANGUL_CHARSET: return "hang";
4991 case RUSSIAN_CHARSET: return "cyrl";
4992 case SHIFTJIS_CHARSET: return "kana";
4993 case TURKISH_CHARSET: return "latn"; /* ?? */
4994 case VIETNAMESE_CHARSET: return "latn";
4995 case JOHAB_CHARSET: return "latn"; /* ?? */
4996 case ARABIC_CHARSET: return "arab";
4997 case HEBREW_CHARSET: return "hebr";
4998 case THAI_CHARSET: return "thai";
4999 default: return "latn";
5003 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5005 const GSUB_Header *header;
5006 const GSUB_Script *script;
5007 const GSUB_LangSys *language;
5008 const GSUB_Feature *feature;
5010 if (!font->GSUB_Table)
5013 header = font->GSUB_Table;
5015 script = GSUB_get_script_table(header, get_opentype_script(font));
5018 TRACE("Script not found\n");
5021 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5024 TRACE("Language not found\n");
5027 feature = GSUB_get_feature(header, language, "vrt2");
5029 feature = GSUB_get_feature(header, language, "vert");
5032 TRACE("vrt2/vert feature not found\n");
5035 return GSUB_apply_feature(header, feature, glyph);
5038 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5042 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5043 WCHAR wc = (WCHAR)glyph;
5045 BOOL *default_used_pointer;
5048 default_used_pointer = NULL;
5049 default_used = FALSE;
5050 if (codepage_sets_default_used(font->codepage))
5051 default_used_pointer = &default_used;
5052 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5055 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5056 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5060 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5062 if (glyph < 0x100) glyph += 0xf000;
5063 /* there is a number of old pre-Unicode "broken" TTFs, which
5064 do have symbols at U+00XX instead of U+f0XX */
5065 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5066 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5068 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5073 /*************************************************************
5074 * freetype_GetGlyphIndices
5076 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5078 struct freetype_physdev *physdev = get_freetype_dev( dev );
5081 BOOL got_default = FALSE;
5085 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5086 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5089 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5091 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5096 EnterCriticalSection( &freetype_cs );
5098 for(i = 0; i < count; i++)
5100 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5105 if (FT_IS_SFNT(physdev->font->ft_face))
5107 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5108 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5113 get_text_metrics(physdev->font, &textm);
5114 default_char = textm.tmDefaultChar;
5118 pgi[i] = default_char;
5121 LeaveCriticalSection( &freetype_cs );
5125 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5127 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5128 return !memcmp(matrix, &identity, sizeof(FMAT2));
5131 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5133 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5134 return !memcmp(matrix, &identity, sizeof(MAT2));
5137 static inline BYTE get_max_level( UINT format )
5141 case GGO_GRAY2_BITMAP: return 4;
5142 case GGO_GRAY4_BITMAP: return 16;
5143 case GGO_GRAY8_BITMAP: return 64;
5148 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5150 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5151 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5154 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5155 FT_Face ft_face = incoming_font->ft_face;
5156 GdiFont *font = incoming_font;
5157 FT_UInt glyph_index;
5158 DWORD width, height, pitch, needed = 0;
5159 FT_Bitmap ft_bitmap;
5161 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5163 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5164 double widthRatio = 1.0;
5165 FT_Matrix transMat = identityMat;
5166 FT_Matrix transMatUnrotated;
5167 BOOL needsTransform = FALSE;
5168 BOOL tategaki = (font->GSUB_Table != NULL);
5169 UINT original_index;
5171 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5172 buflen, buf, lpmat);
5174 TRACE("font transform %f %f %f %f\n",
5175 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5176 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5178 if(format & GGO_GLYPH_INDEX) {
5179 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5180 original_index = glyph;
5181 format &= ~GGO_GLYPH_INDEX;
5183 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5184 ft_face = font->ft_face;
5185 original_index = glyph_index;
5188 if(format & GGO_UNHINTED) {
5189 load_flags |= FT_LOAD_NO_HINTING;
5190 format &= ~GGO_UNHINTED;
5193 /* tategaki never appears to happen to lower glyph index */
5194 if (glyph_index < TATEGAKI_LOWER_BOUND )
5197 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5198 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5199 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5200 font->gmsize * sizeof(GM*));
5202 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5203 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5205 *lpgm = FONT_GM(font,original_index)->gm;
5206 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5207 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5208 lpgm->gmCellIncX, lpgm->gmCellIncY);
5209 return 1; /* FIXME */
5213 if (!font->gm[original_index / GM_BLOCK_SIZE])
5214 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5216 /* Scaling factor */
5221 get_text_metrics(font, &tm);
5223 widthRatio = (double)font->aveWidth;
5224 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5227 widthRatio = font->scale_y;
5229 /* Scaling transform */
5230 if (widthRatio != 1.0 || font->scale_y != 1.0)
5233 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5236 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5238 pFT_Matrix_Multiply(&scaleMat, &transMat);
5239 needsTransform = TRUE;
5242 /* Slant transform */
5243 if (font->fake_italic) {
5246 slantMat.xx = (1 << 16);
5247 slantMat.xy = ((1 << 16) >> 2);
5249 slantMat.yy = (1 << 16);
5250 pFT_Matrix_Multiply(&slantMat, &transMat);
5251 needsTransform = TRUE;
5254 /* Rotation transform */
5255 transMatUnrotated = transMat;
5256 if(font->orientation && !tategaki) {
5257 FT_Matrix rotationMat;
5259 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5260 pFT_Vector_Unit(&vecAngle, angle);
5261 rotationMat.xx = vecAngle.x;
5262 rotationMat.xy = -vecAngle.y;
5263 rotationMat.yx = -rotationMat.xy;
5264 rotationMat.yy = rotationMat.xx;
5266 pFT_Matrix_Multiply(&rotationMat, &transMat);
5267 needsTransform = TRUE;
5270 /* World transform */
5271 if (!is_identity_FMAT2(&font->font_desc.matrix))
5274 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5275 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5276 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5277 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5278 pFT_Matrix_Multiply(&worldMat, &transMat);
5279 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5280 needsTransform = TRUE;
5283 /* Extra transformation specified by caller */
5284 if (!is_identity_MAT2(lpmat))
5287 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5288 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5289 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5290 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5291 pFT_Matrix_Multiply(&extraMat, &transMat);
5292 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5293 needsTransform = TRUE;
5296 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5297 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5298 format == GGO_GRAY8_BITMAP))
5300 load_flags |= FT_LOAD_NO_BITMAP;
5303 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5306 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5310 if(!needsTransform) {
5311 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5312 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5313 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5315 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5316 bottom = (ft_face->glyph->metrics.horiBearingY -
5317 ft_face->glyph->metrics.height) & -64;
5318 lpgm->gmCellIncX = adv;
5319 lpgm->gmCellIncY = 0;
5326 for(xc = 0; xc < 2; xc++) {
5327 for(yc = 0; yc < 2; yc++) {
5328 vec.x = (ft_face->glyph->metrics.horiBearingX +
5329 xc * ft_face->glyph->metrics.width);
5330 vec.y = ft_face->glyph->metrics.horiBearingY -
5331 yc * ft_face->glyph->metrics.height;
5332 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5333 pFT_Vector_Transform(&vec, &transMat);
5334 if(xc == 0 && yc == 0) {
5335 left = right = vec.x;
5336 top = bottom = vec.y;
5338 if(vec.x < left) left = vec.x;
5339 else if(vec.x > right) right = vec.x;
5340 if(vec.y < bottom) bottom = vec.y;
5341 else if(vec.y > top) top = vec.y;
5346 right = (right + 63) & -64;
5347 bottom = bottom & -64;
5348 top = (top + 63) & -64;
5350 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5351 vec.x = ft_face->glyph->metrics.horiAdvance;
5353 pFT_Vector_Transform(&vec, &transMat);
5354 lpgm->gmCellIncX = (vec.x+63) >> 6;
5355 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5357 vec.x = ft_face->glyph->metrics.horiAdvance;
5359 pFT_Vector_Transform(&vec, &transMatUnrotated);
5360 adv = (vec.x+63) >> 6;
5364 bbx = (right - left) >> 6;
5365 lpgm->gmBlackBoxX = (right - left) >> 6;
5366 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5367 lpgm->gmptGlyphOrigin.x = left >> 6;
5368 lpgm->gmptGlyphOrigin.y = top >> 6;
5370 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5371 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5372 lpgm->gmCellIncX, lpgm->gmCellIncY);
5374 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5375 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5377 FONT_GM(font,original_index)->gm = *lpgm;
5378 FONT_GM(font,original_index)->adv = adv;
5379 FONT_GM(font,original_index)->lsb = lsb;
5380 FONT_GM(font,original_index)->bbx = bbx;
5381 FONT_GM(font,original_index)->init = TRUE;
5384 if(format == GGO_METRICS)
5386 return 1; /* FIXME */
5389 if(ft_face->glyph->format != ft_glyph_format_outline &&
5390 (format == GGO_NATIVE || format == GGO_BEZIER))
5392 TRACE("loaded a bitmap\n");
5398 width = lpgm->gmBlackBoxX;
5399 height = lpgm->gmBlackBoxY;
5400 pitch = ((width + 31) >> 5) << 2;
5401 needed = pitch * height;
5403 if(!buf || !buflen) break;
5405 switch(ft_face->glyph->format) {
5406 case ft_glyph_format_bitmap:
5408 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5409 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5410 INT h = ft_face->glyph->bitmap.rows;
5412 memcpy(dst, src, w);
5413 src += ft_face->glyph->bitmap.pitch;
5419 case ft_glyph_format_outline:
5420 ft_bitmap.width = width;
5421 ft_bitmap.rows = height;
5422 ft_bitmap.pitch = pitch;
5423 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5424 ft_bitmap.buffer = buf;
5427 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5429 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5431 /* Note: FreeType will only set 'black' bits for us. */
5432 memset(buf, 0, needed);
5433 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5437 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5442 case GGO_GRAY2_BITMAP:
5443 case GGO_GRAY4_BITMAP:
5444 case GGO_GRAY8_BITMAP:
5445 case WINE_GGO_GRAY16_BITMAP:
5447 unsigned int max_level, row, col;
5450 width = lpgm->gmBlackBoxX;
5451 height = lpgm->gmBlackBoxY;
5452 pitch = (width + 3) / 4 * 4;
5453 needed = pitch * height;
5455 if(!buf || !buflen) break;
5457 max_level = get_max_level( format );
5459 switch(ft_face->glyph->format) {
5460 case ft_glyph_format_bitmap:
5462 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5463 INT h = ft_face->glyph->bitmap.rows;
5465 memset( buf, 0, needed );
5467 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5468 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5469 src += ft_face->glyph->bitmap.pitch;
5474 case ft_glyph_format_outline:
5476 ft_bitmap.width = width;
5477 ft_bitmap.rows = height;
5478 ft_bitmap.pitch = pitch;
5479 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5480 ft_bitmap.buffer = buf;
5483 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5485 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5487 memset(ft_bitmap.buffer, 0, buflen);
5489 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5491 if (max_level != 255)
5493 for (row = 0, start = buf; row < height; row++)
5495 for (col = 0, ptr = start; col < width; col++, ptr++)
5496 *ptr = (((int)*ptr) * max_level + 128) / 256;
5504 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5510 case WINE_GGO_HRGB_BITMAP:
5511 case WINE_GGO_HBGR_BITMAP:
5512 case WINE_GGO_VRGB_BITMAP:
5513 case WINE_GGO_VBGR_BITMAP:
5514 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5516 switch (ft_face->glyph->format)
5518 case FT_GLYPH_FORMAT_BITMAP:
5523 width = lpgm->gmBlackBoxX;
5524 height = lpgm->gmBlackBoxY;
5526 needed = pitch * height;
5528 if (!buf || !buflen) break;
5530 memset(buf, 0, buflen);
5532 src = ft_face->glyph->bitmap.buffer;
5533 src_pitch = ft_face->glyph->bitmap.pitch;
5535 height = min( height, ft_face->glyph->bitmap.rows );
5538 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5540 if ( src[x / 8] & masks[x % 8] )
5541 ((unsigned int *)dst)[x] = ~0u;
5550 case FT_GLYPH_FORMAT_OUTLINE:
5554 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5555 INT x_shift, y_shift;
5557 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5558 FT_Render_Mode render_mode =
5559 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5560 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5562 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5564 if ( render_mode == FT_RENDER_MODE_LCD)
5566 lpgm->gmBlackBoxX += 2;
5567 lpgm->gmptGlyphOrigin.x -= 1;
5571 lpgm->gmBlackBoxY += 2;
5572 lpgm->gmptGlyphOrigin.y += 1;
5576 width = lpgm->gmBlackBoxX;
5577 height = lpgm->gmBlackBoxY;
5579 needed = pitch * height;
5581 if (!buf || !buflen) break;
5583 memset(buf, 0, buflen);
5585 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5587 if ( needsTransform )
5588 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5590 if ( pFT_Library_SetLcdFilter )
5591 pFT_Library_SetLcdFilter( library, lcdfilter );
5592 pFT_Render_Glyph (ft_face->glyph, render_mode);
5594 src = ft_face->glyph->bitmap.buffer;
5595 src_pitch = ft_face->glyph->bitmap.pitch;
5596 src_width = ft_face->glyph->bitmap.width;
5597 src_height = ft_face->glyph->bitmap.rows;
5599 if ( render_mode == FT_RENDER_MODE_LCD)
5607 rgb_interval = src_pitch;
5612 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5613 if ( x_shift < 0 ) x_shift = 0;
5614 if ( x_shift + (src_width / hmul) > width )
5615 x_shift = width - (src_width / hmul);
5617 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5618 if ( y_shift < 0 ) y_shift = 0;
5619 if ( y_shift + (src_height / vmul) > height )
5620 y_shift = height - (src_height / vmul);
5622 dst += x_shift + y_shift * ( pitch / 4 );
5623 while ( src_height )
5625 for ( x = 0; x < src_width / hmul; x++ )
5629 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5630 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5631 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5632 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5636 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5637 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5638 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5639 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5642 src += src_pitch * vmul;
5651 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5663 int contour, point = 0, first_pt;
5664 FT_Outline *outline = &ft_face->glyph->outline;
5665 TTPOLYGONHEADER *pph;
5667 DWORD pph_start, cpfx, type;
5669 if(buflen == 0) buf = NULL;
5671 if (needsTransform && buf) {
5672 pFT_Outline_Transform(outline, &transMat);
5675 for(contour = 0; contour < outline->n_contours; contour++) {
5677 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5680 pph->dwType = TT_POLYGON_TYPE;
5681 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5683 needed += sizeof(*pph);
5685 while(point <= outline->contours[contour]) {
5686 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5687 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5688 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5692 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5695 } while(point <= outline->contours[contour] &&
5696 (outline->tags[point] & FT_Curve_Tag_On) ==
5697 (outline->tags[point-1] & FT_Curve_Tag_On));
5698 /* At the end of a contour Windows adds the start point, but
5700 if(point > outline->contours[contour] &&
5701 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5703 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5705 } else if(point <= outline->contours[contour] &&
5706 outline->tags[point] & FT_Curve_Tag_On) {
5707 /* add closing pt for bezier */
5709 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5717 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5720 pph->cb = needed - pph_start;
5726 /* Convert the quadratic Beziers to cubic Beziers.
5727 The parametric eqn for a cubic Bezier is, from PLRM:
5728 r(t) = at^3 + bt^2 + ct + r0
5729 with the control points:
5734 A quadratic Bezier has the form:
5735 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5737 So equating powers of t leads to:
5738 r1 = 2/3 p1 + 1/3 p0
5739 r2 = 2/3 p1 + 1/3 p2
5740 and of course r0 = p0, r3 = p2
5743 int contour, point = 0, first_pt;
5744 FT_Outline *outline = &ft_face->glyph->outline;
5745 TTPOLYGONHEADER *pph;
5747 DWORD pph_start, cpfx, type;
5748 FT_Vector cubic_control[4];
5749 if(buflen == 0) buf = NULL;
5751 if (needsTransform && buf) {
5752 pFT_Outline_Transform(outline, &transMat);
5755 for(contour = 0; contour < outline->n_contours; contour++) {
5757 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5760 pph->dwType = TT_POLYGON_TYPE;
5761 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5763 needed += sizeof(*pph);
5765 while(point <= outline->contours[contour]) {
5766 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5767 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5768 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5771 if(type == TT_PRIM_LINE) {
5773 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5777 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5780 /* FIXME: Possible optimization in endpoint calculation
5781 if there are two consecutive curves */
5782 cubic_control[0] = outline->points[point-1];
5783 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5784 cubic_control[0].x += outline->points[point].x + 1;
5785 cubic_control[0].y += outline->points[point].y + 1;
5786 cubic_control[0].x >>= 1;
5787 cubic_control[0].y >>= 1;
5789 if(point+1 > outline->contours[contour])
5790 cubic_control[3] = outline->points[first_pt];
5792 cubic_control[3] = outline->points[point+1];
5793 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5794 cubic_control[3].x += outline->points[point].x + 1;
5795 cubic_control[3].y += outline->points[point].y + 1;
5796 cubic_control[3].x >>= 1;
5797 cubic_control[3].y >>= 1;
5800 /* r1 = 1/3 p0 + 2/3 p1
5801 r2 = 1/3 p2 + 2/3 p1 */
5802 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5803 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5804 cubic_control[2] = cubic_control[1];
5805 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5806 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5807 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5808 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5810 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5811 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5812 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5817 } while(point <= outline->contours[contour] &&
5818 (outline->tags[point] & FT_Curve_Tag_On) ==
5819 (outline->tags[point-1] & FT_Curve_Tag_On));
5820 /* At the end of a contour Windows adds the start point,
5821 but only for Beziers and we've already done that.
5823 if(point <= outline->contours[contour] &&
5824 outline->tags[point] & FT_Curve_Tag_On) {
5825 /* This is the closing pt of a bezier, but we've already
5826 added it, so just inc point and carry on */
5833 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5836 pph->cb = needed - pph_start;
5842 FIXME("Unsupported format %d\n", format);
5848 static BOOL get_bitmap_text_metrics(GdiFont *font)
5850 FT_Face ft_face = font->ft_face;
5851 FT_WinFNT_HeaderRec winfnt_header;
5852 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5853 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5854 font->potm->otmSize = size;
5856 #define TM font->potm->otmTextMetrics
5857 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5859 TM.tmHeight = winfnt_header.pixel_height;
5860 TM.tmAscent = winfnt_header.ascent;
5861 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5862 TM.tmInternalLeading = winfnt_header.internal_leading;
5863 TM.tmExternalLeading = winfnt_header.external_leading;
5864 TM.tmAveCharWidth = winfnt_header.avg_width;
5865 TM.tmMaxCharWidth = winfnt_header.max_width;
5866 TM.tmWeight = winfnt_header.weight;
5868 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5869 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5870 TM.tmFirstChar = winfnt_header.first_char;
5871 TM.tmLastChar = winfnt_header.last_char;
5872 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5873 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5874 TM.tmItalic = winfnt_header.italic;
5875 TM.tmUnderlined = font->underline;
5876 TM.tmStruckOut = font->strikeout;
5877 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5878 TM.tmCharSet = winfnt_header.charset;
5882 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5883 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5884 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5885 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5886 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5887 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5888 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5889 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5891 TM.tmDigitizedAspectX = 96; /* FIXME */
5892 TM.tmDigitizedAspectY = 96; /* FIXME */
5894 TM.tmLastChar = 255;
5895 TM.tmDefaultChar = 32;
5896 TM.tmBreakChar = 32;
5897 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5898 TM.tmUnderlined = font->underline;
5899 TM.tmStruckOut = font->strikeout;
5900 /* NB inverted meaning of TMPF_FIXED_PITCH */
5901 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5902 TM.tmCharSet = font->charset;
5910 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5912 double scale_x, scale_y;
5916 scale_x = (double)font->aveWidth;
5917 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5920 scale_x = font->scale_y;
5922 scale_x *= fabs(font->font_desc.matrix.eM11);
5923 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5925 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5926 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5928 SCALE_Y(ptm->tmHeight);
5929 SCALE_Y(ptm->tmAscent);
5930 SCALE_Y(ptm->tmDescent);
5931 SCALE_Y(ptm->tmInternalLeading);
5932 SCALE_Y(ptm->tmExternalLeading);
5933 SCALE_Y(ptm->tmOverhang);
5935 SCALE_X(ptm->tmAveCharWidth);
5936 SCALE_X(ptm->tmMaxCharWidth);
5942 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5944 double scale_x, scale_y;
5948 scale_x = (double)font->aveWidth;
5949 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5952 scale_x = font->scale_y;
5954 scale_x *= fabs(font->font_desc.matrix.eM11);
5955 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5957 scale_font_metrics(font, &potm->otmTextMetrics);
5959 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5960 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5962 SCALE_Y(potm->otmAscent);
5963 SCALE_Y(potm->otmDescent);
5964 SCALE_Y(potm->otmLineGap);
5965 SCALE_Y(potm->otmsCapEmHeight);
5966 SCALE_Y(potm->otmsXHeight);
5967 SCALE_Y(potm->otmrcFontBox.top);
5968 SCALE_Y(potm->otmrcFontBox.bottom);
5969 SCALE_X(potm->otmrcFontBox.left);
5970 SCALE_X(potm->otmrcFontBox.right);
5971 SCALE_Y(potm->otmMacAscent);
5972 SCALE_Y(potm->otmMacDescent);
5973 SCALE_Y(potm->otmMacLineGap);
5974 SCALE_X(potm->otmptSubscriptSize.x);
5975 SCALE_Y(potm->otmptSubscriptSize.y);
5976 SCALE_X(potm->otmptSubscriptOffset.x);
5977 SCALE_Y(potm->otmptSubscriptOffset.y);
5978 SCALE_X(potm->otmptSuperscriptSize.x);
5979 SCALE_Y(potm->otmptSuperscriptSize.y);
5980 SCALE_X(potm->otmptSuperscriptOffset.x);
5981 SCALE_Y(potm->otmptSuperscriptOffset.y);
5982 SCALE_Y(potm->otmsStrikeoutSize);
5983 SCALE_Y(potm->otmsStrikeoutPosition);
5984 SCALE_Y(potm->otmsUnderscoreSize);
5985 SCALE_Y(potm->otmsUnderscorePosition);
5991 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5995 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5997 /* Make sure that the font has sane width/height ratio */
6000 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6002 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6007 *ptm = font->potm->otmTextMetrics;
6008 scale_font_metrics(font, ptm);
6012 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6016 for(i = 0; i < ft_face->num_charmaps; i++)
6018 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6024 static BOOL get_outline_text_metrics(GdiFont *font)
6027 FT_Face ft_face = font->ft_face;
6028 UINT needed, lenfam, lensty;
6030 TT_HoriHeader *pHori;
6031 TT_Postscript *pPost;
6032 FT_Fixed x_scale, y_scale;
6033 WCHAR *family_nameW, *style_nameW;
6034 static const WCHAR spaceW[] = {' ', '\0'};
6036 INT ascent, descent;
6038 TRACE("font=%p\n", font);
6040 if(!FT_IS_SCALABLE(ft_face))
6043 needed = sizeof(*font->potm);
6045 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6046 family_nameW = strdupW(font->name);
6048 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6050 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6051 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6052 style_nameW, lensty/sizeof(WCHAR));
6054 /* These names should be read from the TT name table */
6056 /* length of otmpFamilyName */
6059 /* length of otmpFaceName */
6060 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6061 needed += lenfam; /* just the family name */
6063 needed += lenfam + lensty; /* family + " " + style */
6066 /* length of otmpStyleName */
6069 /* length of otmpFullName */
6070 needed += lenfam + lensty;
6073 x_scale = ft_face->size->metrics.x_scale;
6074 y_scale = ft_face->size->metrics.y_scale;
6076 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6078 FIXME("Can't find OS/2 table - not TT font?\n");
6082 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6084 FIXME("Can't find HHEA table - not TT font?\n");
6088 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6090 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6091 pOS2->usWinAscent, pOS2->usWinDescent,
6092 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6093 ft_face->ascender, ft_face->descender, ft_face->height,
6094 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6095 ft_face->bbox.yMax, ft_face->bbox.yMin);
6097 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6098 font->potm->otmSize = needed;
6100 #define TM font->potm->otmTextMetrics
6102 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6103 ascent = pHori->Ascender;
6104 descent = -pHori->Descender;
6106 ascent = pOS2->usWinAscent;
6107 descent = pOS2->usWinDescent;
6111 TM.tmAscent = font->yMax;
6112 TM.tmDescent = -font->yMin;
6113 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6115 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6116 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6117 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6118 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6121 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6124 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6126 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6127 ((ascent + descent) -
6128 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6130 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6131 if (TM.tmAveCharWidth == 0) {
6132 TM.tmAveCharWidth = 1;
6134 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6135 TM.tmWeight = FW_REGULAR;
6136 if (font->fake_bold)
6137 TM.tmWeight = FW_BOLD;
6140 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6142 if (pOS2->usWeightClass > FW_MEDIUM)
6143 TM.tmWeight = pOS2->usWeightClass;
6145 else if (pOS2->usWeightClass <= FW_MEDIUM)
6146 TM.tmWeight = pOS2->usWeightClass;
6149 TM.tmDigitizedAspectX = 300;
6150 TM.tmDigitizedAspectY = 300;
6151 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6152 * symbol range to 0 - f0ff
6155 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6160 case 1257: /* Baltic */
6161 TM.tmLastChar = 0xf8fd;
6164 TM.tmLastChar = 0xf0ff;
6166 TM.tmBreakChar = 0x20;
6167 TM.tmDefaultChar = 0x1f;
6171 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6172 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6174 if(pOS2->usFirstCharIndex <= 1)
6175 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6176 else if (pOS2->usFirstCharIndex > 0xff)
6177 TM.tmBreakChar = 0x20;
6179 TM.tmBreakChar = pOS2->usFirstCharIndex;
6180 TM.tmDefaultChar = TM.tmBreakChar - 1;
6182 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6183 TM.tmUnderlined = font->underline;
6184 TM.tmStruckOut = font->strikeout;
6186 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6187 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6188 (pOS2->version == 0xFFFFU ||
6189 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6190 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6192 TM.tmPitchAndFamily = 0;
6194 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6196 case PAN_FAMILY_SCRIPT:
6197 TM.tmPitchAndFamily |= FF_SCRIPT;
6200 case PAN_FAMILY_DECORATIVE:
6201 TM.tmPitchAndFamily |= FF_DECORATIVE;
6206 case PAN_FAMILY_TEXT_DISPLAY:
6207 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6208 /* which is clearly not what the panose spec says. */
6210 if(TM.tmPitchAndFamily == 0 || /* fixed */
6211 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6212 TM.tmPitchAndFamily = FF_MODERN;
6215 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6220 TM.tmPitchAndFamily |= FF_DONTCARE;
6223 case PAN_SERIF_COVE:
6224 case PAN_SERIF_OBTUSE_COVE:
6225 case PAN_SERIF_SQUARE_COVE:
6226 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6227 case PAN_SERIF_SQUARE:
6228 case PAN_SERIF_THIN:
6229 case PAN_SERIF_BONE:
6230 case PAN_SERIF_EXAGGERATED:
6231 case PAN_SERIF_TRIANGLE:
6232 TM.tmPitchAndFamily |= FF_ROMAN;
6235 case PAN_SERIF_NORMAL_SANS:
6236 case PAN_SERIF_OBTUSE_SANS:
6237 case PAN_SERIF_PERP_SANS:
6238 case PAN_SERIF_FLARED:
6239 case PAN_SERIF_ROUNDED:
6240 TM.tmPitchAndFamily |= FF_SWISS;
6247 if(FT_IS_SCALABLE(ft_face))
6248 TM.tmPitchAndFamily |= TMPF_VECTOR;
6250 if(FT_IS_SFNT(ft_face))
6252 if (font->ntmFlags & NTM_PS_OPENTYPE)
6253 TM.tmPitchAndFamily |= TMPF_DEVICE;
6255 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6258 TM.tmCharSet = font->charset;
6260 font->potm->otmFiller = 0;
6261 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6262 font->potm->otmfsSelection = pOS2->fsSelection;
6263 font->potm->otmfsType = pOS2->fsType;
6264 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6265 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6266 font->potm->otmItalicAngle = 0; /* POST table */
6267 font->potm->otmEMSquare = ft_face->units_per_EM;
6268 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6269 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6270 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6271 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6272 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6273 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6274 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6275 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6276 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6277 font->potm->otmMacAscent = TM.tmAscent;
6278 font->potm->otmMacDescent = -TM.tmDescent;
6279 font->potm->otmMacLineGap = font->potm->otmLineGap;
6280 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6281 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6282 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6283 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6284 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6285 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6286 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6287 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6288 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6289 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6290 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6292 font->potm->otmsUnderscoreSize = 0;
6293 font->potm->otmsUnderscorePosition = 0;
6295 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6296 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6300 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6301 cp = (char*)font->potm + sizeof(*font->potm);
6302 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6303 strcpyW((WCHAR*)cp, family_nameW);
6305 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6306 strcpyW((WCHAR*)cp, style_nameW);
6308 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6309 strcpyW((WCHAR*)cp, family_nameW);
6310 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6311 strcatW((WCHAR*)cp, spaceW);
6312 strcatW((WCHAR*)cp, style_nameW);
6313 cp += lenfam + lensty;
6316 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6317 strcpyW((WCHAR*)cp, family_nameW);
6318 strcatW((WCHAR*)cp, spaceW);
6319 strcatW((WCHAR*)cp, style_nameW);
6323 HeapFree(GetProcessHeap(), 0, style_nameW);
6324 HeapFree(GetProcessHeap(), 0, family_nameW);
6328 /*************************************************************
6329 * freetype_GetGlyphOutline
6331 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6332 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6334 struct freetype_physdev *physdev = get_freetype_dev( dev );
6339 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6340 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6344 EnterCriticalSection( &freetype_cs );
6345 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6346 LeaveCriticalSection( &freetype_cs );
6350 /*************************************************************
6351 * freetype_GetTextMetrics
6353 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6355 struct freetype_physdev *physdev = get_freetype_dev( dev );
6360 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6361 return dev->funcs->pGetTextMetrics( dev, metrics );
6365 EnterCriticalSection( &freetype_cs );
6366 ret = get_text_metrics( physdev->font, metrics );
6367 LeaveCriticalSection( &freetype_cs );
6371 /*************************************************************
6372 * freetype_GetOutlineTextMetrics
6374 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6376 struct freetype_physdev *physdev = get_freetype_dev( dev );
6381 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6382 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6385 TRACE("font=%p\n", physdev->font);
6387 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6390 EnterCriticalSection( &freetype_cs );
6392 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6394 if(cbSize >= physdev->font->potm->otmSize)
6396 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6397 scale_outline_font_metrics(physdev->font, potm);
6399 ret = physdev->font->potm->otmSize;
6401 LeaveCriticalSection( &freetype_cs );
6405 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6407 HFONTLIST *hfontlist;
6408 child->font = alloc_font();
6409 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6410 if(!child->font->ft_face)
6412 free_font(child->font);
6417 child->font->font_desc = font->font_desc;
6418 child->font->ntmFlags = child->face->ntmFlags;
6419 child->font->orientation = font->orientation;
6420 child->font->scale_y = font->scale_y;
6421 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6422 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6423 child->font->name = strdupW(child->face->family->FamilyName);
6424 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6425 child->font->base_font = font;
6426 list_add_head(&child_font_list, &child->font->entry);
6427 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6431 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6434 CHILD_FONT *child_font;
6437 font = font->base_font;
6439 *linked_font = font;
6441 if((*glyph = get_glyph_index(font, c)))
6443 *glyph = get_GSUB_vert_glyph(font, *glyph);
6447 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6449 if(!child_font->font)
6450 if(!load_child_font(font, child_font))
6453 if(!child_font->font->ft_face)
6455 g = get_glyph_index(child_font->font, c);
6456 g = get_GSUB_vert_glyph(child_font->font, g);
6460 *linked_font = child_font->font;
6467 /*************************************************************
6468 * freetype_GetCharWidth
6470 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6472 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6475 FT_UInt glyph_index;
6476 GdiFont *linked_font;
6477 struct freetype_physdev *physdev = get_freetype_dev( dev );
6481 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6482 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6485 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6488 EnterCriticalSection( &freetype_cs );
6489 for(c = firstChar; c <= lastChar; c++) {
6490 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6491 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6492 &gm, 0, NULL, &identity);
6493 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6495 LeaveCriticalSection( &freetype_cs );
6499 /*************************************************************
6500 * freetype_GetCharABCWidths
6502 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6504 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6507 FT_UInt glyph_index;
6508 GdiFont *linked_font;
6509 struct freetype_physdev *physdev = get_freetype_dev( dev );
6513 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6514 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6517 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6520 EnterCriticalSection( &freetype_cs );
6522 for(c = firstChar; c <= lastChar; c++) {
6523 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6524 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6525 &gm, 0, NULL, &identity);
6526 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6527 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6528 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6529 FONT_GM(linked_font,glyph_index)->bbx;
6531 LeaveCriticalSection( &freetype_cs );
6535 /*************************************************************
6536 * freetype_GetCharABCWidthsI
6538 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6540 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6543 FT_UInt glyph_index;
6544 GdiFont *linked_font;
6545 struct freetype_physdev *physdev = get_freetype_dev( dev );
6549 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6550 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6553 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6557 EnterCriticalSection( &freetype_cs );
6559 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6561 for(c = firstChar; c < firstChar+count; c++) {
6562 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6563 &gm, 0, NULL, &identity);
6564 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6565 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6566 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6567 - FONT_GM(linked_font,c)->bbx;
6570 for(c = 0; c < count; c++) {
6571 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6572 &gm, 0, NULL, &identity);
6573 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6574 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6575 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6576 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6579 LeaveCriticalSection( &freetype_cs );
6583 /*************************************************************
6584 * freetype_GetTextExtentExPoint
6586 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6587 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6589 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6594 FT_UInt glyph_index;
6595 GdiFont *linked_font;
6596 struct freetype_physdev *physdev = get_freetype_dev( dev );
6600 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6601 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6604 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6607 EnterCriticalSection( &freetype_cs );
6610 get_text_metrics( physdev->font, &tm );
6611 size->cy = tm.tmHeight;
6613 for(idx = 0; idx < count; idx++) {
6614 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6615 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6616 &gm, 0, NULL, &identity);
6617 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6619 if (! pnfit || ext <= max_ext) {
6629 LeaveCriticalSection( &freetype_cs );
6630 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6634 /*************************************************************
6635 * freetype_GetTextExtentExPointI
6637 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6638 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6640 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6645 struct freetype_physdev *physdev = get_freetype_dev( dev );
6649 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6650 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6653 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6656 EnterCriticalSection( &freetype_cs );
6659 get_text_metrics(physdev->font, &tm);
6660 size->cy = tm.tmHeight;
6662 for(idx = 0; idx < count; idx++) {
6663 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6664 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6666 if (! pnfit || ext <= max_ext) {
6676 LeaveCriticalSection( &freetype_cs );
6677 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6681 /*************************************************************
6682 * freetype_GetFontData
6684 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6686 struct freetype_physdev *physdev = get_freetype_dev( dev );
6690 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6691 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6694 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6695 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6696 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6698 return get_font_data( physdev->font, table, offset, buf, cbData );
6701 /*************************************************************
6702 * freetype_GetTextFace
6704 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6707 struct freetype_physdev *physdev = get_freetype_dev( dev );
6711 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6712 return dev->funcs->pGetTextFace( dev, count, str );
6715 n = strlenW(physdev->font->name) + 1;
6718 lstrcpynW(str, physdev->font->name, count);
6724 /*************************************************************
6725 * freetype_GetTextCharsetInfo
6727 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6729 struct freetype_physdev *physdev = get_freetype_dev( dev );
6733 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6734 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6736 if (fs) *fs = physdev->font->fs;
6737 return physdev->font->charset;
6740 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6742 GdiFont *font = dc->gdiFont, *linked_font;
6743 struct list *first_hfont;
6747 EnterCriticalSection( &freetype_cs );
6748 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6749 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6750 if(font == linked_font)
6751 *new_hfont = dc->hFont;
6754 first_hfont = list_head(&linked_font->hfontlist);
6755 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6757 LeaveCriticalSection( &freetype_cs );
6761 /* Retrieve a list of supported Unicode ranges for a given font.
6762 * Can be called with NULL gs to calculate the buffer size. Returns
6763 * the number of ranges found.
6765 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6767 DWORD num_ranges = 0;
6769 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6772 FT_ULong char_code, char_code_prev;
6775 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6777 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6778 face->num_glyphs, glyph_code, char_code);
6780 if (!glyph_code) return 0;
6784 gs->ranges[0].wcLow = (USHORT)char_code;
6785 gs->ranges[0].cGlyphs = 0;
6786 gs->cGlyphsSupported = 0;
6792 if (char_code < char_code_prev)
6794 ERR("expected increasing char code from FT_Get_Next_Char\n");
6797 if (char_code - char_code_prev > 1)
6802 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6803 gs->ranges[num_ranges - 1].cGlyphs = 1;
6804 gs->cGlyphsSupported++;
6809 gs->ranges[num_ranges - 1].cGlyphs++;
6810 gs->cGlyphsSupported++;
6812 char_code_prev = char_code;
6813 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6817 FIXME("encoding %u not supported\n", face->charmap->encoding);
6822 /*************************************************************
6823 * freetype_GetFontUnicodeRanges
6825 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6827 struct freetype_physdev *physdev = get_freetype_dev( dev );
6828 DWORD size, num_ranges;
6832 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6833 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6836 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6837 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6840 glyphset->cbThis = size;
6841 glyphset->cRanges = num_ranges;
6842 glyphset->flAccel = 0;
6847 /*************************************************************
6848 * freetype_FontIsLinked
6850 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6852 struct freetype_physdev *physdev = get_freetype_dev( dev );
6857 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6858 return dev->funcs->pFontIsLinked( dev );
6862 EnterCriticalSection( &freetype_cs );
6863 ret = !list_empty(&physdev->font->child_fonts);
6864 LeaveCriticalSection( &freetype_cs );
6868 static BOOL is_hinting_enabled(void)
6870 /* Use the >= 2.2.0 function if available */
6871 if(pFT_Get_TrueType_Engine_Type)
6873 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6874 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6876 #ifdef FT_DRIVER_HAS_HINTER
6881 /* otherwise if we've been compiled with < 2.2.0 headers
6882 use the internal macro */
6883 mod = pFT_Get_Module(library, "truetype");
6884 if(mod && FT_DRIVER_HAS_HINTER(mod))
6892 static BOOL is_subpixel_rendering_enabled( void )
6894 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6895 return pFT_Library_SetLcdFilter &&
6896 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6902 /*************************************************************************
6903 * GetRasterizerCaps (GDI32.@)
6905 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6907 static int hinting = -1;
6908 static int subpixel = -1;
6912 hinting = is_hinting_enabled();
6913 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6916 if ( subpixel == -1 )
6918 subpixel = is_subpixel_rendering_enabled();
6919 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6922 lprs->nSize = sizeof(RASTERIZER_STATUS);
6923 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6925 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6926 lprs->nLanguageID = 0;
6930 /*************************************************************
6931 * freetype_GdiRealizationInfo
6933 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6935 struct freetype_physdev *physdev = get_freetype_dev( dev );
6936 realization_info_t *info = ptr;
6940 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6941 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6944 FIXME("(%p, %p): stub!\n", physdev->font, info);
6947 if(FT_IS_SCALABLE(physdev->font->ft_face))
6950 info->cache_num = physdev->font->cache_num;
6951 info->unknown2 = -1;
6955 /*************************************************************************
6956 * Kerning support for TrueType fonts
6958 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6960 struct TT_kern_table
6966 struct TT_kern_subtable
6975 USHORT horizontal : 1;
6977 USHORT cross_stream: 1;
6978 USHORT override : 1;
6979 USHORT reserved1 : 4;
6985 struct TT_format0_kern_subtable
6989 USHORT entrySelector;
7000 static DWORD parse_format0_kern_subtable(GdiFont *font,
7001 const struct TT_format0_kern_subtable *tt_f0_ks,
7002 const USHORT *glyph_to_char,
7003 KERNINGPAIR *kern_pair, DWORD cPairs)
7006 const struct TT_kern_pair *tt_kern_pair;
7008 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7010 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7012 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7013 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7014 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7016 if (!kern_pair || !cPairs)
7019 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7021 nPairs = min(nPairs, cPairs);
7023 for (i = 0; i < nPairs; i++)
7025 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7026 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7027 /* this algorithm appears to better match what Windows does */
7028 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7029 if (kern_pair->iKernAmount < 0)
7031 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7032 kern_pair->iKernAmount -= font->ppem;
7034 else if (kern_pair->iKernAmount > 0)
7036 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7037 kern_pair->iKernAmount += font->ppem;
7039 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7041 TRACE("left %u right %u value %d\n",
7042 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7046 TRACE("copied %u entries\n", nPairs);
7050 /*************************************************************
7051 * freetype_GetKerningPairs
7053 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7057 const struct TT_kern_table *tt_kern_table;
7058 const struct TT_kern_subtable *tt_kern_subtable;
7060 USHORT *glyph_to_char;
7062 struct freetype_physdev *physdev = get_freetype_dev( dev );
7064 if (!(font = physdev->font))
7066 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7067 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7071 EnterCriticalSection( &freetype_cs );
7072 if (font->total_kern_pairs != (DWORD)-1)
7074 if (cPairs && kern_pair)
7076 cPairs = min(cPairs, font->total_kern_pairs);
7077 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7079 else cPairs = font->total_kern_pairs;
7081 LeaveCriticalSection( &freetype_cs );
7085 font->total_kern_pairs = 0;
7087 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7089 if (length == GDI_ERROR)
7091 TRACE("no kerning data in the font\n");
7092 LeaveCriticalSection( &freetype_cs );
7096 buf = HeapAlloc(GetProcessHeap(), 0, length);
7099 WARN("Out of memory\n");
7100 LeaveCriticalSection( &freetype_cs );
7104 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7106 /* build a glyph index to char code map */
7107 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7110 WARN("Out of memory allocating a glyph index to char code map\n");
7111 HeapFree(GetProcessHeap(), 0, buf);
7112 LeaveCriticalSection( &freetype_cs );
7116 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7122 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7124 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7125 font->ft_face->num_glyphs, glyph_code, char_code);
7129 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7131 /* FIXME: This doesn't match what Windows does: it does some fancy
7132 * things with duplicate glyph index to char code mappings, while
7133 * we just avoid overriding existing entries.
7135 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7136 glyph_to_char[glyph_code] = (USHORT)char_code;
7138 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7145 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7146 for (n = 0; n <= 65535; n++)
7147 glyph_to_char[n] = (USHORT)n;
7150 tt_kern_table = buf;
7151 nTables = GET_BE_WORD(tt_kern_table->nTables);
7152 TRACE("version %u, nTables %u\n",
7153 GET_BE_WORD(tt_kern_table->version), nTables);
7155 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7157 for (i = 0; i < nTables; i++)
7159 struct TT_kern_subtable tt_kern_subtable_copy;
7161 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7162 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7163 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7165 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7166 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7167 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7169 /* According to the TrueType specification this is the only format
7170 * that will be properly interpreted by Windows and OS/2
7172 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7174 DWORD new_chunk, old_total = font->total_kern_pairs;
7176 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7177 glyph_to_char, NULL, 0);
7178 font->total_kern_pairs += new_chunk;
7180 if (!font->kern_pairs)
7181 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7182 font->total_kern_pairs * sizeof(*font->kern_pairs));
7184 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7185 font->total_kern_pairs * sizeof(*font->kern_pairs));
7187 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7188 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7191 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7193 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7196 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7197 HeapFree(GetProcessHeap(), 0, buf);
7199 if (cPairs && kern_pair)
7201 cPairs = min(cPairs, font->total_kern_pairs);
7202 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7204 else cPairs = font->total_kern_pairs;
7206 LeaveCriticalSection( &freetype_cs );
7210 static const struct gdi_dc_funcs freetype_funcs =
7212 NULL, /* pAbortDoc */
7213 NULL, /* pAbortPath */
7214 NULL, /* pAlphaBlend */
7215 NULL, /* pAngleArc */
7218 NULL, /* pBeginPath */
7219 NULL, /* pBlendImage */
7220 NULL, /* pChoosePixelFormat */
7222 NULL, /* pCloseFigure */
7223 NULL, /* pCopyBitmap */
7224 NULL, /* pCreateBitmap */
7225 NULL, /* pCreateCompatibleDC */
7226 freetype_CreateDC, /* pCreateDC */
7227 NULL, /* pDeleteBitmap */
7228 freetype_DeleteDC, /* pDeleteDC */
7229 NULL, /* pDeleteObject */
7230 NULL, /* pDescribePixelFormat */
7231 NULL, /* pDeviceCapabilities */
7232 NULL, /* pEllipse */
7234 NULL, /* pEndPage */
7235 NULL, /* pEndPath */
7236 freetype_EnumFonts, /* pEnumFonts */
7237 NULL, /* pEnumICMProfiles */
7238 NULL, /* pExcludeClipRect */
7239 NULL, /* pExtDeviceMode */
7240 NULL, /* pExtEscape */
7241 NULL, /* pExtFloodFill */
7242 NULL, /* pExtSelectClipRgn */
7243 NULL, /* pExtTextOut */
7244 NULL, /* pFillPath */
7245 NULL, /* pFillRgn */
7246 NULL, /* pFlattenPath */
7247 freetype_FontIsLinked, /* pFontIsLinked */
7248 NULL, /* pFrameRgn */
7249 NULL, /* pGdiComment */
7250 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7251 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7252 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7253 freetype_GetCharWidth, /* pGetCharWidth */
7254 NULL, /* pGetDeviceCaps */
7255 NULL, /* pGetDeviceGammaRamp */
7256 freetype_GetFontData, /* pGetFontData */
7257 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7258 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7259 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7260 NULL, /* pGetICMProfile */
7261 NULL, /* pGetImage */
7262 freetype_GetKerningPairs, /* pGetKerningPairs */
7263 NULL, /* pGetNearestColor */
7264 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7265 NULL, /* pGetPixel */
7266 NULL, /* pGetPixelFormat */
7267 NULL, /* pGetSystemPaletteEntries */
7268 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7269 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7270 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7271 freetype_GetTextFace, /* pGetTextFace */
7272 freetype_GetTextMetrics, /* pGetTextMetrics */
7273 NULL, /* pGradientFill */
7274 NULL, /* pIntersectClipRect */
7275 NULL, /* pInvertRgn */
7277 NULL, /* pModifyWorldTransform */
7279 NULL, /* pOffsetClipRgn */
7280 NULL, /* pOffsetViewportOrg */
7281 NULL, /* pOffsetWindowOrg */
7282 NULL, /* pPaintRgn */
7285 NULL, /* pPolyBezier */
7286 NULL, /* pPolyBezierTo */
7287 NULL, /* pPolyDraw */
7288 NULL, /* pPolyPolygon */
7289 NULL, /* pPolyPolyline */
7290 NULL, /* pPolygon */
7291 NULL, /* pPolyline */
7292 NULL, /* pPolylineTo */
7293 NULL, /* pPutImage */
7294 NULL, /* pRealizeDefaultPalette */
7295 NULL, /* pRealizePalette */
7296 NULL, /* pRectangle */
7297 NULL, /* pResetDC */
7298 NULL, /* pRestoreDC */
7299 NULL, /* pRoundRect */
7301 NULL, /* pScaleViewportExt */
7302 NULL, /* pScaleWindowExt */
7303 NULL, /* pSelectBitmap */
7304 NULL, /* pSelectBrush */
7305 NULL, /* pSelectClipPath */
7306 freetype_SelectFont, /* pSelectFont */
7307 NULL, /* pSelectPalette */
7308 NULL, /* pSelectPen */
7309 NULL, /* pSetArcDirection */
7310 NULL, /* pSetBkColor */
7311 NULL, /* pSetBkMode */
7312 NULL, /* pSetDCBrushColor */
7313 NULL, /* pSetDCPenColor */
7314 NULL, /* pSetDIBColorTable */
7315 NULL, /* pSetDIBitsToDevice */
7316 NULL, /* pSetDeviceClipping */
7317 NULL, /* pSetDeviceGammaRamp */
7318 NULL, /* pSetLayout */
7319 NULL, /* pSetMapMode */
7320 NULL, /* pSetMapperFlags */
7321 NULL, /* pSetPixel */
7322 NULL, /* pSetPixelFormat */
7323 NULL, /* pSetPolyFillMode */
7324 NULL, /* pSetROP2 */
7325 NULL, /* pSetRelAbs */
7326 NULL, /* pSetStretchBltMode */
7327 NULL, /* pSetTextAlign */
7328 NULL, /* pSetTextCharacterExtra */
7329 NULL, /* pSetTextColor */
7330 NULL, /* pSetTextJustification */
7331 NULL, /* pSetViewportExt */
7332 NULL, /* pSetViewportOrg */
7333 NULL, /* pSetWindowExt */
7334 NULL, /* pSetWindowOrg */
7335 NULL, /* pSetWorldTransform */
7336 NULL, /* pStartDoc */
7337 NULL, /* pStartPage */
7338 NULL, /* pStretchBlt */
7339 NULL, /* pStretchDIBits */
7340 NULL, /* pStrokeAndFillPath */
7341 NULL, /* pStrokePath */
7342 NULL, /* pSwapBuffers */
7343 NULL, /* pUnrealizePalette */
7344 NULL, /* pWidenPath */
7345 /* OpenGL not supported */
7348 #else /* HAVE_FREETYPE */
7350 /*************************************************************************/
7352 BOOL WineEngInit(void)
7356 BOOL WineEngDestroyFontInstance(HFONT hfont)
7361 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7363 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7367 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7369 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7373 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7375 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7379 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7384 /*************************************************************************
7385 * GetRasterizerCaps (GDI32.@)
7387 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7389 lprs->nSize = sizeof(RASTERIZER_STATUS);
7391 lprs->nLanguageID = 0;
7395 #endif /* HAVE_FREETYPE */