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;
268 FONTSIGNATURE fs_links;
270 FT_Fixed font_version;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
275 struct tagFamily *family;
276 /* Cached data for Enum */
277 struct enum_data *cached_enum_data;
280 typedef struct tagFamily {
282 const WCHAR *FamilyName;
283 const WCHAR *EnglishName;
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;
357 struct enum_charset_element {
360 WCHAR name[LF_FACESIZE];
363 struct enum_charset_list {
365 struct enum_charset_element element[32];
368 #define GM_BLOCK_SIZE 128
369 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
371 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
372 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
373 #define UNUSED_CACHE_SIZE 10
374 static struct list child_font_list = LIST_INIT(child_font_list);
375 static struct list system_links = LIST_INIT(system_links);
377 static struct list font_subst_list = LIST_INIT(font_subst_list);
379 static struct list font_list = LIST_INIT(font_list);
381 struct freetype_physdev
383 struct gdi_physdev dev;
387 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
389 return (struct freetype_physdev *)dev;
392 static const struct gdi_dc_funcs freetype_funcs;
394 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
395 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
396 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
398 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
399 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
400 'W','i','n','d','o','w','s','\\',
401 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
402 'F','o','n','t','s','\0'};
404 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
405 'W','i','n','d','o','w','s',' ','N','T','\\',
406 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
407 'F','o','n','t','s','\0'};
409 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
410 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
411 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
412 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
414 static const WCHAR * const SystemFontValues[] = {
421 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
422 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
424 /* Interesting and well-known (frequently-assumed!) font names */
425 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
426 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 };
427 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
428 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
429 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
430 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
431 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
432 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
434 static const WCHAR arial[] = {'A','r','i','a','l',0};
435 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
436 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};
437 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};
438 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
439 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
440 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
441 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
442 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
443 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
445 static const WCHAR *default_serif_list[] =
449 bitstream_vera_serif,
453 static const WCHAR *default_fixed_list[] =
457 bitstream_vera_sans_mono,
461 static const WCHAR *default_sans_list[] =
474 typedef struct tagFontSubst {
480 /* Registry font cache key and value names */
481 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
482 'F','o','n','t','s',0};
483 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
484 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
485 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
486 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
487 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
488 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
489 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
490 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
491 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
492 static const WCHAR face_size_value[] = {'S','i','z','e',0};
493 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
494 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
495 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
496 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
497 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
510 static struct list mappings_list = LIST_INIT( mappings_list );
512 static CRITICAL_SECTION freetype_cs;
513 static CRITICAL_SECTION_DEBUG critsect_debug =
516 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
517 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
519 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
521 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
523 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
524 static BOOL use_default_fallback = FALSE;
526 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
527 static BOOL get_outline_text_metrics(GdiFont *font);
528 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
530 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
531 'W','i','n','d','o','w','s',' ','N','T','\\',
532 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
533 'S','y','s','t','e','m','L','i','n','k',0};
535 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
536 'F','o','n','t','L','i','n','k','\\',
537 'S','y','s','t','e','m','L','i','n','k',0};
539 /****************************************
540 * Notes on .fon files
542 * The fonts System, FixedSys and Terminal are special. There are typically multiple
543 * versions installed for different resolutions and codepages. Windows stores which one to use
544 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
546 * FIXEDFON.FON FixedSys
548 * OEMFONT.FON Terminal
549 * LogPixels Current dpi set by the display control panel applet
550 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
551 * also has a LogPixels value that appears to mirror this)
553 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
554 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
555 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
556 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
557 * so that makes sense.
559 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
560 * to be mapped into the registry on Windows 2000 at least).
563 * ega80woa.fon=ega80850.fon
564 * ega40woa.fon=ega40850.fon
565 * cga80woa.fon=cga80850.fon
566 * cga40woa.fon=cga40850.fon
569 /* These are all structures needed for the GSUB table */
571 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
572 #define TATEGAKI_LOWER_BOUND 0x02F1
588 GSUB_ScriptRecord ScriptRecord[1];
594 } GSUB_LangSysRecord;
599 GSUB_LangSysRecord LangSysRecord[1];
603 WORD LookupOrder; /* Reserved */
604 WORD ReqFeatureIndex;
606 WORD FeatureIndex[1];
612 } GSUB_FeatureRecord;
616 GSUB_FeatureRecord FeatureRecord[1];
620 WORD FeatureParams; /* Reserved */
622 WORD LookupListIndex[1];
641 } GSUB_CoverageFormat1;
646 WORD StartCoverageIndex;
652 GSUB_RangeRecord RangeRecord[1];
653 } GSUB_CoverageFormat2;
656 WORD SubstFormat; /* = 1 */
659 } GSUB_SingleSubstFormat1;
662 WORD SubstFormat; /* = 2 */
666 }GSUB_SingleSubstFormat2;
668 #ifdef HAVE_CARBON_CARBON_H
669 static char *find_cache_dir(void)
673 static char cached_path[MAX_PATH];
674 static const char *wine = "/Wine", *fonts = "/Fonts";
676 if(*cached_path) return cached_path;
678 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
681 WARN("can't create cached data folder\n");
684 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
687 WARN("can't create cached data path\n");
691 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
693 ERR("Could not create full path\n");
697 strcat(cached_path, wine);
699 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
701 WARN("Couldn't mkdir %s\n", cached_path);
705 strcat(cached_path, fonts);
706 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
708 WARN("Couldn't mkdir %s\n", cached_path);
715 /******************************************************************
718 * Extracts individual TrueType font files from a Mac suitcase font
719 * and saves them into the user's caches directory (see
721 * Returns a NULL terminated array of filenames.
723 * We do this because they are apps that try to read ttf files
724 * themselves and they don't like Mac suitcase files.
726 static char **expand_mac_font(const char *path)
733 const char *filename;
737 unsigned int size, max_size;
740 TRACE("path %s\n", path);
742 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
745 WARN("failed to get ref\n");
749 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
752 TRACE("no data fork, so trying resource fork\n");
753 res_ref = FSOpenResFile(&ref, fsRdPerm);
756 TRACE("unable to open resource fork\n");
763 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
766 CloseResFile(res_ref);
770 out_dir = find_cache_dir();
772 filename = strrchr(path, '/');
773 if(!filename) filename = path;
776 /* output filename has the form out_dir/filename_%04x.ttf */
777 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
784 unsigned short *num_faces_ptr, num_faces, face;
787 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
789 fond = Get1IndResource(fond_res, idx);
791 TRACE("got fond resource %d\n", idx);
794 fam_rec = *(FamRec**)fond;
795 num_faces_ptr = (unsigned short *)(fam_rec + 1);
796 num_faces = GET_BE_WORD(*num_faces_ptr);
798 assoc = (AsscEntry*)(num_faces_ptr + 1);
799 TRACE("num faces %04x\n", num_faces);
800 for(face = 0; face < num_faces; face++, assoc++)
803 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
804 unsigned short size, font_id;
807 size = GET_BE_WORD(assoc->fontSize);
808 font_id = GET_BE_WORD(assoc->fontID);
811 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
815 TRACE("trying to load sfnt id %04x\n", font_id);
816 sfnt = GetResource(sfnt_res, font_id);
819 TRACE("can't get sfnt resource %04x\n", font_id);
823 output = HeapAlloc(GetProcessHeap(), 0, output_len);
828 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
830 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
831 if(fd != -1 || errno == EEXIST)
835 unsigned char *sfnt_data;
838 sfnt_data = *(unsigned char**)sfnt;
839 write(fd, sfnt_data, GetHandleSize(sfnt));
843 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
846 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
848 ret.array[ret.size++] = output;
852 WARN("unable to create %s\n", output);
853 HeapFree(GetProcessHeap(), 0, output);
856 ReleaseResource(sfnt);
859 ReleaseResource(fond);
862 CloseResFile(res_ref);
867 #endif /* HAVE_CARBON_CARBON_H */
869 static inline BOOL is_win9x(void)
871 return GetVersion() & 0x80000000;
874 This function builds an FT_Fixed from a double. It fails if the absolute
875 value of the float number is greater than 32768.
877 static inline FT_Fixed FT_FixedFromFloat(double f)
883 This function builds an FT_Fixed from a FIXED. It simply put f.value
884 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
886 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
888 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
892 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
897 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
898 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
900 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
901 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
903 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
905 if(face_name && strcmpiW(face_name, family->FamilyName))
907 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
911 file = strrchr(face->file, '/');
916 if(!strcasecmp(file, file_nameA))
918 HeapFree(GetProcessHeap(), 0, file_nameA);
923 HeapFree(GetProcessHeap(), 0, file_nameA);
927 static Family *find_family_from_name(const WCHAR *name)
931 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
933 if(!strcmpiW(family->FamilyName, name))
940 static Family *find_family_from_any_name(const WCHAR *name)
944 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
946 if(!strcmpiW(family->FamilyName, name))
948 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
955 static void DumpSubstList(void)
959 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
961 if(psub->from.charset != -1 || psub->to.charset != -1)
962 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
963 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
965 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
966 debugstr_w(psub->to.name));
971 static LPWSTR strdupW(LPCWSTR p)
974 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
975 ret = HeapAlloc(GetProcessHeap(), 0, len);
980 static LPSTR strdupA(LPCSTR p)
983 DWORD len = (strlen(p) + 1);
984 ret = HeapAlloc(GetProcessHeap(), 0, len);
989 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
994 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
996 if(!strcmpiW(element->from.name, from_name) &&
997 (element->from.charset == from_charset ||
998 element->from.charset == -1))
1005 #define ADD_FONT_SUBST_FORCE 1
1007 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1009 FontSubst *from_exist, *to_exist;
1011 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1013 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1015 list_remove(&from_exist->entry);
1016 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1017 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1018 HeapFree(GetProcessHeap(), 0, from_exist);
1024 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1028 HeapFree(GetProcessHeap(), 0, subst->to.name);
1029 subst->to.name = strdupW(to_exist->to.name);
1032 list_add_tail(subst_list, &subst->entry);
1037 HeapFree(GetProcessHeap(), 0, subst->from.name);
1038 HeapFree(GetProcessHeap(), 0, subst->to.name);
1039 HeapFree(GetProcessHeap(), 0, subst);
1043 static WCHAR *towstr(UINT cp, const char *str)
1048 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1049 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1050 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1054 static void split_subst_info(NameCs *nc, LPSTR str)
1056 CHAR *p = strrchr(str, ',');
1060 nc->charset = strtol(p+1, NULL, 10);
1063 nc->name = towstr(CP_ACP, str);
1066 static void LoadSubstList(void)
1070 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1074 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1075 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1076 &hkey) == ERROR_SUCCESS) {
1078 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1079 &valuelen, &datalen, NULL, NULL);
1081 valuelen++; /* returned value doesn't include room for '\0' */
1082 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1083 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1087 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1088 &dlen) == ERROR_SUCCESS) {
1089 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1091 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1092 split_subst_info(&psub->from, value);
1093 split_subst_info(&psub->to, data);
1095 /* Win 2000 doesn't allow mapping between different charsets
1096 or mapping of DEFAULT_CHARSET */
1097 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1098 psub->to.charset == DEFAULT_CHARSET) {
1099 HeapFree(GetProcessHeap(), 0, psub->to.name);
1100 HeapFree(GetProcessHeap(), 0, psub->from.name);
1101 HeapFree(GetProcessHeap(), 0, psub);
1103 add_font_subst(&font_subst_list, psub, 0);
1105 /* reset dlen and vlen */
1109 HeapFree(GetProcessHeap(), 0, data);
1110 HeapFree(GetProcessHeap(), 0, value);
1116 /*****************************************************************
1117 * get_name_table_entry
1119 * Supply the platform, encoding, language and name ids in req
1120 * and if the name exists the function will fill in the string
1121 * and string_len members. The string is owned by FreeType so
1122 * don't free it. Returns TRUE if the name is found else FALSE.
1124 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1127 FT_UInt num_names, name_index;
1129 if(FT_IS_SFNT(ft_face))
1131 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1133 for(name_index = 0; name_index < num_names; name_index++)
1135 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1137 if((name.platform_id == req->platform_id) &&
1138 (name.encoding_id == req->encoding_id) &&
1139 (name.language_id == req->language_id) &&
1140 (name.name_id == req->name_id))
1142 req->string = name.string;
1143 req->string_len = name.string_len;
1150 req->string_len = 0;
1154 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1159 name.platform_id = TT_PLATFORM_MICROSOFT;
1160 name.encoding_id = TT_MS_ID_UNICODE_CS;
1161 name.language_id = language_id;
1162 name.name_id = name_id;
1164 if(get_name_table_entry(ft_face, &name))
1168 /* String is not nul terminated and string_len is a byte length. */
1169 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1170 for(i = 0; i < name.string_len / 2; i++)
1172 WORD *tmp = (WORD *)&name.string[i * 2];
1173 ret[i] = GET_BE_WORD(*tmp);
1176 TRACE("Got localised name %s\n", debugstr_w(ret));
1182 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1185 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1186 if(r != ERROR_SUCCESS) return r;
1187 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1188 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1191 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1193 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1196 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1199 DWORD num_strikes, max_strike_key_len;
1201 /* If we have a File Name key then this is a real font, not just the parent
1202 key of a bunch of non-scalable strikes */
1203 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1207 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1208 face->cached_enum_data = NULL;
1210 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1211 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1213 face->StyleName = strdupW(face_name);
1214 face->family = family;
1215 face->vertical = (family->FamilyName[0] == '@');
1217 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1219 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1220 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1221 face->FullName = fullName;
1224 face->FullName = NULL;
1226 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1227 reg_load_dword(hkey_face, face_italic_value, &italic);
1228 reg_load_dword(hkey_face, face_bold_value, &bold);
1229 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1230 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1232 needed = sizeof(face->fs);
1233 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1234 memset(&face->fs_links, 0, sizeof(face->fs_links));
1236 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1238 face->scalable = TRUE;
1239 memset(&face->size, 0, sizeof(face->size));
1243 face->scalable = FALSE;
1244 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1245 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1246 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1247 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1248 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1250 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1251 face->size.height, face->size.width, face->size.size >> 6,
1252 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1256 if (italic) face->ntmFlags |= NTM_ITALIC;
1257 if (bold) face->ntmFlags |= NTM_BOLD;
1258 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1260 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1261 face->fs.fsCsb[0], face->fs.fsCsb[1],
1262 face->fs.fsUsb[0], face->fs.fsUsb[1],
1263 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1265 if(!italic && !bold)
1266 list_add_head(&family->faces, &face->entry);
1268 list_add_tail(&family->faces, &face->entry);
1270 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1273 /* do we have any bitmap strikes? */
1274 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1275 NULL, NULL, NULL, NULL);
1276 if(num_strikes != 0)
1278 WCHAR strike_name[10];
1279 DWORD strike_index = 0;
1281 needed = sizeof(strike_name) / sizeof(WCHAR);
1282 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1283 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1286 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1287 load_face(hkey_strike, face_name, family);
1288 RegCloseKey(hkey_strike);
1289 needed = sizeof(strike_name) / sizeof(WCHAR);
1294 static void load_font_list_from_cache(HKEY hkey_font_cache)
1296 DWORD max_family_key_len, size;
1298 DWORD family_index = 0;
1302 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1303 NULL, NULL, NULL, NULL);
1304 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1306 size = max_family_key_len + 1;
1307 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1308 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1310 WCHAR *english_family = NULL;
1311 DWORD face_index = 0;
1313 DWORD max_face_key_len;
1315 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1316 TRACE("opened family key %s\n", debugstr_w(family_name));
1317 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1319 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1320 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1323 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1324 family->FamilyName = strdupW(family_name);
1325 family->EnglishName = english_family;
1326 list_init(&family->faces);
1327 list_add_tail(&font_list, &family->entry);
1331 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1332 subst->from.name = strdupW(english_family);
1333 subst->from.charset = -1;
1334 subst->to.name = strdupW(family_name);
1335 subst->to.charset = -1;
1336 add_font_subst(&font_subst_list, subst, 0);
1339 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1340 NULL, NULL, NULL, NULL);
1342 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1343 size = max_face_key_len + 1;
1344 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1345 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1349 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1350 load_face(hkey_face, face_name, family);
1351 RegCloseKey(hkey_face);
1352 size = max_face_key_len + 1;
1354 HeapFree(GetProcessHeap(), 0, face_name);
1355 RegCloseKey(hkey_family);
1356 size = max_family_key_len + 1;
1359 HeapFree(GetProcessHeap(), 0, family_name);
1362 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1365 HKEY hkey_wine_fonts;
1367 /* We don't want to create the fonts key as volatile, so open this first */
1368 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1369 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1370 if(ret != ERROR_SUCCESS)
1372 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1376 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1377 KEY_ALL_ACCESS, NULL, hkey, disposition);
1378 RegCloseKey(hkey_wine_fonts);
1382 static void add_face_to_cache(Face *face)
1384 HKEY hkey_font_cache, hkey_family, hkey_face;
1385 WCHAR *face_key_name;
1387 create_font_cache_key(&hkey_font_cache, NULL);
1389 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1390 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1391 if(face->family->EnglishName)
1392 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1393 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1396 face_key_name = face->StyleName;
1399 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1400 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1401 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1403 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1406 HeapFree(GetProcessHeap(), 0, face_key_name);
1408 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1410 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1411 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1413 reg_save_dword(hkey_face, face_index_value, face->face_index);
1414 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1415 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1416 reg_save_dword(hkey_face, face_version_value, face->font_version);
1417 reg_save_dword(hkey_face, face_external_value, face->external);
1419 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1423 reg_save_dword(hkey_face, face_height_value, face->size.height);
1424 reg_save_dword(hkey_face, face_width_value, face->size.width);
1425 reg_save_dword(hkey_face, face_size_value, face->size.size);
1426 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1427 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1428 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1430 RegCloseKey(hkey_face);
1431 RegCloseKey(hkey_family);
1432 RegCloseKey(hkey_font_cache);
1435 static inline int TestStyles(DWORD flags, DWORD styles)
1437 return (flags & styles) == styles;
1440 static int StyleOrdering(Face *face)
1442 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1444 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1446 if (TestStyles(face->ntmFlags, NTM_BOLD))
1448 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1451 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1452 debugstr_w(face->family->FamilyName),
1453 debugstr_w(face->StyleName),
1459 /* Add a style of face to a font family using an ordering of the list such
1460 that regular fonts come before bold and italic, and single styles come
1461 before compound styles. */
1462 static void AddFaceToFamily(Face *face, Family *family)
1466 LIST_FOR_EACH( entry, &family->faces )
1468 Face *ent = LIST_ENTRY(entry, Face, entry);
1469 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1471 list_add_before( entry, &face->entry );
1474 static WCHAR *prepend_at(WCHAR *family)
1481 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1483 strcpyW(str + 1, family);
1484 HeapFree(GetProcessHeap(), 0, family);
1488 #define ADDFONT_EXTERNAL_FONT 0x01
1489 #define ADDFONT_FORCE_BITMAP 0x02
1490 #define ADDFONT_ADD_TO_CACHE 0x04
1492 static void AddFaceToList(FT_Face ft_face, char *fake_family, const char *file, void *font_data_ptr, DWORD font_data_size, FT_Long face_index, DWORD flags, BOOL vertical)
1501 WCHAR *english_family, *localised_family;
1503 struct list *face_elem_ptr;
1504 FT_WinFNT_HeaderRec winfnt_header;
1505 int internal_leading;
1507 My_FT_Bitmap_Size *size = NULL;
1510 if(!FT_IS_SCALABLE(ft_face))
1511 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1515 english_family = towstr(CP_ACP, fake_family);
1516 localised_family = NULL;
1520 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1521 if (!english_family)
1522 english_family = towstr(CP_ACP, ft_face->family_name);
1524 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1525 if (localised_family && !strcmpiW(localised_family, english_family))
1527 HeapFree(GetProcessHeap(), 0, localised_family);
1528 localised_family = NULL;
1534 english_family = prepend_at(english_family);
1535 localised_family = prepend_at(localised_family);
1538 family = find_family_from_name(localised_family ? localised_family : english_family);
1540 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1541 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1542 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1543 list_init(&family->faces);
1544 list_add_tail(&font_list, &family->entry);
1546 if(localised_family) {
1547 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1548 subst->from.name = strdupW(english_family);
1549 subst->from.charset = -1;
1550 subst->to.name = strdupW(localised_family);
1551 subst->to.charset = -1;
1552 add_font_subst(&font_subst_list, subst, 0);
1555 HeapFree(GetProcessHeap(), 0, localised_family);
1556 HeapFree(GetProcessHeap(), 0, english_family);
1558 StyleW = towstr(CP_ACP, ft_face->style_name);
1560 internal_leading = 0;
1561 memset(&fs, 0, sizeof(fs));
1563 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1565 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1566 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1567 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1568 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1569 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1570 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1571 if(pOS2->version == 0) {
1574 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1575 fs.fsCsb[0] |= FS_LATIN1;
1577 fs.fsCsb[0] |= FS_SYMBOL;
1580 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1582 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1583 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1584 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1586 internal_leading = winfnt_header.internal_leading;
1589 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1590 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1591 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1592 if(!strcmpiW(face->StyleName, StyleW) &&
1593 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1594 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1595 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1596 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1599 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1600 HeapFree(GetProcessHeap(), 0, StyleW);
1603 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1604 TRACE("Original font is newer so skipping this one\n");
1605 HeapFree(GetProcessHeap(), 0, StyleW);
1608 TRACE("Replacing original with this one\n");
1609 list_remove(&face->entry);
1610 HeapFree(GetProcessHeap(), 0, face->file);
1611 HeapFree(GetProcessHeap(), 0, face->StyleName);
1612 HeapFree(GetProcessHeap(), 0, face->FullName);
1613 HeapFree(GetProcessHeap(), 0, face);
1618 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1619 face->cached_enum_data = NULL;
1620 face->StyleName = StyleW;
1621 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1624 face->file = strdupA(file);
1625 face->font_data_ptr = NULL;
1626 face->font_data_size = 0;
1631 face->font_data_ptr = font_data_ptr;
1632 face->font_data_size = font_data_size;
1634 face->face_index = face_index;
1636 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1637 face->ntmFlags |= NTM_ITALIC;
1638 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1639 face->ntmFlags |= NTM_BOLD;
1640 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1641 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1642 face->family = family;
1643 face->vertical = vertical;
1644 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1646 memset(&face->fs_links, 0, sizeof(face->fs_links));
1648 if(FT_IS_SCALABLE(ft_face)) {
1649 memset(&face->size, 0, sizeof(face->size));
1650 face->scalable = TRUE;
1652 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1653 size->height, size->width, size->size >> 6,
1654 size->x_ppem >> 6, size->y_ppem >> 6);
1655 face->size.height = size->height;
1656 face->size.width = size->width;
1657 face->size.size = size->size;
1658 face->size.x_ppem = size->x_ppem;
1659 face->size.y_ppem = size->y_ppem;
1660 face->size.internal_leading = internal_leading;
1661 face->scalable = FALSE;
1664 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1666 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1668 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1669 face->ntmFlags |= NTM_PS_OPENTYPE;
1672 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1673 face->fs.fsCsb[0], face->fs.fsCsb[1],
1674 face->fs.fsUsb[0], face->fs.fsUsb[1],
1675 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1677 if(face->fs.fsCsb[0] == 0)
1681 /* let's see if we can find any interesting cmaps */
1682 for(i = 0; i < ft_face->num_charmaps; i++) {
1683 switch(ft_face->charmaps[i]->encoding) {
1684 case FT_ENCODING_UNICODE:
1685 case FT_ENCODING_APPLE_ROMAN:
1686 face->fs.fsCsb[0] |= FS_LATIN1;
1688 case FT_ENCODING_MS_SYMBOL:
1689 face->fs.fsCsb[0] |= FS_SYMBOL;
1697 if(flags & ADDFONT_ADD_TO_CACHE)
1698 add_face_to_cache(face);
1700 AddFaceToFamily(face, family);
1702 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1704 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1705 debugstr_w(StyleW));
1708 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1712 TT_Header *pHeader = NULL;
1713 WCHAR *localised_family;
1715 FT_Long face_index = 0, num_faces;
1718 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1719 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1721 #ifdef HAVE_CARBON_CARBON_H
1722 if(file && !fake_family)
1724 char **mac_list = expand_mac_font(file);
1727 BOOL had_one = FALSE;
1729 for(cursor = mac_list; *cursor; cursor++)
1732 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1733 HeapFree(GetProcessHeap(), 0, *cursor);
1735 HeapFree(GetProcessHeap(), 0, mac_list);
1740 #endif /* HAVE_CARBON_CARBON_H */
1745 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1746 err = pFT_New_Face(library, file, face_index, &ft_face);
1749 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1750 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1754 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1758 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*/
1759 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1760 pFT_Done_Face(ft_face);
1764 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1765 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1766 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1767 pFT_Done_Face(ft_face);
1771 if(FT_IS_SFNT(ft_face))
1773 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1774 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1775 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1777 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1778 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1779 pFT_Done_Face(ft_face);
1783 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1784 we don't want to load these. */
1785 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1789 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1791 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1792 pFT_Done_Face(ft_face);
1798 if(!ft_face->family_name || !ft_face->style_name) {
1799 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1800 pFT_Done_Face(ft_face);
1804 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1806 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1807 pFT_Done_Face(ft_face);
1813 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1814 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1816 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1817 HeapFree(GetProcessHeap(), 0, localised_family);
1818 num_faces = ft_face->num_faces;
1819 pFT_Done_Face(ft_face);
1822 HeapFree(GetProcessHeap(), 0, localised_family);
1825 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1828 if (FT_HAS_VERTICAL(ft_face))
1830 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1834 num_faces = ft_face->num_faces;
1835 pFT_Done_Face(ft_face);
1836 } while(num_faces > ++face_index);
1840 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1842 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1845 static void DumpFontList(void)
1849 struct list *family_elem_ptr, *face_elem_ptr;
1851 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1852 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1853 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1854 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1855 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1856 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1858 TRACE(" %d", face->size.height);
1865 /***********************************************************
1866 * The replacement list is a way to map an entire font
1867 * family onto another family. For example adding
1869 * [HKCU\Software\Wine\Fonts\Replacements]
1870 * "Wingdings"="Winedings"
1872 * would enumerate the Winedings font both as Winedings and
1873 * Wingdings. However if a real Wingdings font is present the
1874 * replacement does not take place.
1877 static void LoadReplaceList(void)
1880 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1885 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1886 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1888 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1889 &valuelen, &datalen, NULL, NULL);
1891 valuelen++; /* returned value doesn't include room for '\0' */
1892 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1893 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1897 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1898 &dlen) == ERROR_SUCCESS) {
1899 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1900 /* "NewName"="Oldname" */
1901 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1903 if(!find_family_from_any_name(value))
1905 /* Find the old family and hence all of the font files
1907 const Family * const family = find_family_from_any_name(data);
1910 const struct list *face_elem_ptr;
1911 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1912 const Face * const face = LIST_ENTRY(face_elem_ptr, Face, entry);
1913 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1914 debugstr_w(face->StyleName), familyA);
1915 /* Now add a new entry with the new family name */
1916 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1917 familyA, family->FamilyName,
1918 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1923 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1928 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1930 /* reset dlen and vlen */
1934 HeapFree(GetProcessHeap(), 0, data);
1935 HeapFree(GetProcessHeap(), 0, value);
1940 static const WCHAR *font_links_list[] =
1942 Lucida_Sans_Unicode,
1943 Microsoft_Sans_Serif,
1947 static const struct font_links_defaults_list
1949 /* Keyed off substitution for "MS Shell Dlg" */
1950 const WCHAR *shelldlg;
1951 /* Maximum of four substitutes, plus terminating NULL pointer */
1952 const WCHAR *substitutes[5];
1953 } font_links_defaults_list[] =
1955 /* Non East-Asian */
1956 { Tahoma, /* FIXME unverified ordering */
1957 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
1959 /* Below lists are courtesy of
1960 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1964 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
1966 /* Chinese Simplified */
1968 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
1972 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
1974 /* Chinese Traditional */
1976 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
1981 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
1994 SYSTEM_LINKS *font_link;
1995 BOOL existing = FALSE;
1997 memset(&fs, 0, sizeof(fs));
1998 psub = get_font_subst(&font_subst_list, name, -1);
1999 /* Don't store fonts that are only substitutes for other fonts */
2002 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2006 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2008 if(!strcmpiW(font_link->font_name, name))
2017 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2018 font_link->font_name = strdupW(name);
2019 list_init(&font_link->links);
2022 for (i = 0; values[i] != NULL; i++)
2024 CHILD_FONT *child_font;
2027 if (!strcmpiW(name,value))
2029 psub = get_font_subst(&font_subst_list, value, -1);
2031 value = psub->to.name;
2032 family = find_family_from_name(value);
2036 /* Use first extant filename for this Family */
2037 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2041 file = strrchr(face->file, '/');
2050 fileW = towstr(CP_UNIXCP, file);
2052 face = find_face_from_filename(fileW, value);
2055 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2059 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2060 child_font->face = face;
2061 child_font->font = NULL;
2062 fs.fsCsb[0] |= face->fs.fsCsb[0];
2063 fs.fsCsb[1] |= face->fs.fsCsb[1];
2064 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2065 list_add_tail(&font_link->links, &child_font->entry);
2067 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2068 HeapFree(GetProcessHeap(), 0, fileW);
2071 family = find_family_from_name(font_link->font_name);
2074 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2076 face->fs_links = fs;
2080 list_add_tail(&system_links, &font_link->entry);
2085 /*************************************************************
2088 static BOOL init_system_links(void)
2092 DWORD type, max_val, max_data, val_len, data_len, index;
2093 WCHAR *value, *data;
2094 WCHAR *entry, *next;
2095 SYSTEM_LINKS *font_link, *system_font_link;
2096 CHILD_FONT *child_font;
2097 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2098 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2099 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2106 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2108 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2109 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2110 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2111 val_len = max_val + 1;
2112 data_len = max_data;
2114 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2116 memset(&fs, 0, sizeof(fs));
2117 psub = get_font_subst(&font_subst_list, value, -1);
2118 /* Don't store fonts that are only substitutes for other fonts */
2121 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2124 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2125 font_link->font_name = strdupW(value);
2126 list_init(&font_link->links);
2127 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2130 CHILD_FONT *child_font;
2132 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2134 next = entry + strlenW(entry) + 1;
2136 face_name = strchrW(entry, ',');
2140 while(isspaceW(*face_name))
2143 psub = get_font_subst(&font_subst_list, face_name, -1);
2145 face_name = psub->to.name;
2147 face = find_face_from_filename(entry, face_name);
2150 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2154 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2155 child_font->face = face;
2156 child_font->font = NULL;
2157 fs.fsCsb[0] |= face->fs.fsCsb[0];
2158 fs.fsCsb[1] |= face->fs.fsCsb[1];
2159 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2160 list_add_tail(&font_link->links, &child_font->entry);
2162 family = find_family_from_name(font_link->font_name);
2165 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2167 face->fs_links = fs;
2170 list_add_tail(&system_links, &font_link->entry);
2172 val_len = max_val + 1;
2173 data_len = max_data;
2176 HeapFree(GetProcessHeap(), 0, value);
2177 HeapFree(GetProcessHeap(), 0, data);
2182 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2184 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2188 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2190 const FontSubst *psub2;
2191 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2193 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2195 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2196 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2198 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2199 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2201 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2203 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2209 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2212 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2213 system_font_link->font_name = strdupW(System);
2214 list_init(&system_font_link->links);
2215 memset(&fs, 0, sizeof(fs));
2217 face = find_face_from_filename(tahoma_ttf, Tahoma);
2220 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2221 child_font->face = face;
2222 child_font->font = NULL;
2223 fs.fsCsb[0] |= face->fs.fsCsb[0];
2224 fs.fsCsb[1] |= face->fs.fsCsb[1];
2225 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2226 list_add_tail(&system_font_link->links, &child_font->entry);
2228 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2230 if(!strcmpiW(font_link->font_name, Tahoma))
2232 CHILD_FONT *font_link_entry;
2233 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2235 CHILD_FONT *new_child;
2236 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2237 new_child->face = font_link_entry->face;
2238 new_child->font = NULL;
2239 fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2240 fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2241 list_add_tail(&system_font_link->links, &new_child->entry);
2246 family = find_family_from_name(system_font_link->font_name);
2249 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2251 face->fs_links = fs;
2254 list_add_tail(&system_links, &system_font_link->entry);
2258 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2261 struct dirent *dent;
2262 char path[MAX_PATH];
2264 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2266 dir = opendir(dirname);
2268 WARN("Can't open directory %s\n", debugstr_a(dirname));
2271 while((dent = readdir(dir)) != NULL) {
2272 struct stat statbuf;
2274 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2277 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2279 sprintf(path, "%s/%s", dirname, dent->d_name);
2281 if(stat(path, &statbuf) == -1)
2283 WARN("Can't stat %s\n", debugstr_a(path));
2286 if(S_ISDIR(statbuf.st_mode))
2287 ReadFontDir(path, external_fonts);
2290 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2291 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2292 AddFontFileToList(path, NULL, NULL, addfont_flags);
2299 static void load_fontconfig_fonts(void)
2301 #ifdef SONAME_LIBFONTCONFIG
2302 void *fc_handle = NULL;
2311 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2313 TRACE("Wine cannot find the fontconfig library (%s).\n",
2314 SONAME_LIBFONTCONFIG);
2317 #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;}
2318 LOAD_FUNCPTR(FcConfigGetCurrent);
2319 LOAD_FUNCPTR(FcFontList);
2320 LOAD_FUNCPTR(FcFontSetDestroy);
2321 LOAD_FUNCPTR(FcInit);
2322 LOAD_FUNCPTR(FcObjectSetAdd);
2323 LOAD_FUNCPTR(FcObjectSetCreate);
2324 LOAD_FUNCPTR(FcObjectSetDestroy);
2325 LOAD_FUNCPTR(FcPatternCreate);
2326 LOAD_FUNCPTR(FcPatternDestroy);
2327 LOAD_FUNCPTR(FcPatternGetBool);
2328 LOAD_FUNCPTR(FcPatternGetString);
2331 if(!pFcInit()) return;
2333 config = pFcConfigGetCurrent();
2334 pat = pFcPatternCreate();
2335 os = pFcObjectSetCreate();
2336 pFcObjectSetAdd(os, FC_FILE);
2337 pFcObjectSetAdd(os, FC_SCALABLE);
2338 fontset = pFcFontList(config, pat, os);
2339 if(!fontset) return;
2340 for(i = 0; i < fontset->nfont; i++) {
2343 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2345 TRACE("fontconfig: %s\n", file);
2347 /* We're just interested in OT/TT fonts for now, so this hack just
2348 picks up the scalable fonts without extensions .pf[ab] to save time
2349 loading every other font */
2351 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2353 TRACE("not scalable\n");
2357 len = strlen( file );
2358 if(len < 4) continue;
2359 ext = &file[ len - 3 ];
2360 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2361 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2363 pFcFontSetDestroy(fontset);
2364 pFcObjectSetDestroy(os);
2365 pFcPatternDestroy(pat);
2371 static BOOL load_font_from_data_dir(LPCWSTR file)
2374 const char *data_dir = wine_get_data_dir();
2376 if (!data_dir) data_dir = wine_get_build_dir();
2383 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2385 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2387 strcpy(unix_name, data_dir);
2388 strcat(unix_name, "/fonts/");
2390 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2392 EnterCriticalSection( &freetype_cs );
2393 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2394 LeaveCriticalSection( &freetype_cs );
2395 HeapFree(GetProcessHeap(), 0, unix_name);
2400 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2402 static const WCHAR slashW[] = {'\\','\0'};
2404 WCHAR windowsdir[MAX_PATH];
2407 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2408 strcatW(windowsdir, fontsW);
2409 strcatW(windowsdir, slashW);
2410 strcatW(windowsdir, file);
2411 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2412 EnterCriticalSection( &freetype_cs );
2413 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2414 LeaveCriticalSection( &freetype_cs );
2415 HeapFree(GetProcessHeap(), 0, unixname);
2420 static void load_system_fonts(void)
2423 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2424 const WCHAR * const *value;
2426 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2429 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2430 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2431 strcatW(windowsdir, fontsW);
2432 for(value = SystemFontValues; *value; value++) {
2433 dlen = sizeof(data);
2434 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2438 sprintfW(pathW, fmtW, windowsdir, data);
2439 if((unixname = wine_get_unix_file_name(pathW))) {
2440 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2441 HeapFree(GetProcessHeap(), 0, unixname);
2444 load_font_from_data_dir(data);
2451 /*************************************************************
2453 * This adds registry entries for any externally loaded fonts
2454 * (fonts from fontconfig or FontDirs). It also deletes entries
2455 * of no longer existing fonts.
2458 static void update_reg_entries(void)
2460 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2465 struct list *family_elem_ptr, *face_elem_ptr;
2467 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2468 static const WCHAR spaceW[] = {' ', '\0'};
2471 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2472 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2473 ERR("Can't create Windows font reg key\n");
2477 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2478 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2479 ERR("Can't create Windows font reg key\n");
2483 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2484 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2485 ERR("Can't create external font reg key\n");
2489 /* enumerate the fonts and add external ones to the two keys */
2491 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2492 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2493 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2494 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2495 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2496 if(!face->external) continue;
2498 if (!(face->ntmFlags & NTM_REGULAR))
2499 len = len_fam + strlenW(face->StyleName) + 1;
2500 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2501 strcpyW(valueW, family->FamilyName);
2502 if(len != len_fam) {
2503 strcatW(valueW, spaceW);
2504 strcatW(valueW, face->StyleName);
2506 strcatW(valueW, TrueType);
2508 file = wine_get_dos_file_name(face->file);
2510 len = strlenW(file) + 1;
2513 if((path = strrchr(face->file, '/')) == NULL)
2517 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2519 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2520 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2522 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2523 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2524 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2526 HeapFree(GetProcessHeap(), 0, file);
2527 HeapFree(GetProcessHeap(), 0, valueW);
2531 if(external_key) RegCloseKey(external_key);
2532 if(win9x_key) RegCloseKey(win9x_key);
2533 if(winnt_key) RegCloseKey(winnt_key);
2537 static void delete_external_font_keys(void)
2539 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2540 DWORD dlen, vlen, datalen, valuelen, i, type;
2544 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2545 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2546 ERR("Can't create Windows font reg key\n");
2550 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2551 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2552 ERR("Can't create Windows font reg key\n");
2556 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2557 ERR("Can't create external font reg key\n");
2561 /* Delete all external fonts added last time */
2563 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2564 &valuelen, &datalen, NULL, NULL);
2565 valuelen++; /* returned value doesn't include room for '\0' */
2566 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2567 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2569 dlen = datalen * sizeof(WCHAR);
2572 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2573 &dlen) == ERROR_SUCCESS) {
2575 RegDeleteValueW(winnt_key, valueW);
2576 RegDeleteValueW(win9x_key, valueW);
2577 /* reset dlen and vlen */
2581 HeapFree(GetProcessHeap(), 0, data);
2582 HeapFree(GetProcessHeap(), 0, valueW);
2584 /* Delete the old external fonts key */
2585 RegCloseKey(external_key);
2586 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2589 if(win9x_key) RegCloseKey(win9x_key);
2590 if(winnt_key) RegCloseKey(winnt_key);
2593 /*************************************************************
2594 * WineEngAddFontResourceEx
2597 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2603 if (ft_handle) /* do it only if we have freetype up and running */
2608 FIXME("Ignoring flags %x\n", flags);
2610 if((unixname = wine_get_unix_file_name(file)))
2612 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2614 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2615 EnterCriticalSection( &freetype_cs );
2616 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2617 LeaveCriticalSection( &freetype_cs );
2618 HeapFree(GetProcessHeap(), 0, unixname);
2620 if (!ret && !strchrW(file, '\\')) {
2621 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2622 ret = load_font_from_winfonts_dir(file);
2624 /* Try in datadir/fonts (or builddir/fonts),
2625 * needed for Magic the Gathering Online
2627 ret = load_font_from_data_dir(file);
2634 /*************************************************************
2635 * WineEngAddFontMemResourceEx
2638 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2642 if (ft_handle) /* do it only if we have freetype up and running */
2644 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2646 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2647 memcpy(pFontCopy, pbFont, cbFont);
2649 EnterCriticalSection( &freetype_cs );
2650 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2651 LeaveCriticalSection( &freetype_cs );
2655 TRACE("AddFontToList failed\n");
2656 HeapFree(GetProcessHeap(), 0, pFontCopy);
2659 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2660 * For now return something unique but quite random
2662 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2663 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2670 /*************************************************************
2671 * WineEngRemoveFontResourceEx
2674 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2677 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2681 static const struct nls_update_font_list
2683 UINT ansi_cp, oem_cp;
2684 const char *oem, *fixed, *system;
2685 const char *courier, *serif, *small, *sserif;
2686 /* these are for font substitutes */
2687 const char *shelldlg, *tmsrmn;
2688 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2692 const char *from, *to;
2693 } arial_0, courier_new_0, times_new_roman_0;
2694 } nls_update_font_list[] =
2696 /* Latin 1 (United States) */
2697 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2698 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2699 "Tahoma","Times New Roman",
2700 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2703 /* Latin 1 (Multilingual) */
2704 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2705 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2706 "Tahoma","Times New Roman", /* FIXME unverified */
2707 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2710 /* Eastern Europe */
2711 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2712 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2713 "Tahoma","Times New Roman", /* FIXME unverified */
2714 "Fixedsys,238", "System,238",
2715 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2716 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2717 { "Arial CE,0", "Arial,238" },
2718 { "Courier New CE,0", "Courier New,238" },
2719 { "Times New Roman CE,0", "Times New Roman,238" }
2722 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2723 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2724 "Tahoma","Times New Roman", /* FIXME unverified */
2725 "Fixedsys,204", "System,204",
2726 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2727 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2728 { "Arial Cyr,0", "Arial,204" },
2729 { "Courier New Cyr,0", "Courier New,204" },
2730 { "Times New Roman Cyr,0", "Times New Roman,204" }
2733 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2734 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2735 "Tahoma","Times New Roman", /* FIXME unverified */
2736 "Fixedsys,161", "System,161",
2737 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2738 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2739 { "Arial Greek,0", "Arial,161" },
2740 { "Courier New Greek,0", "Courier New,161" },
2741 { "Times New Roman Greek,0", "Times New Roman,161" }
2744 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2745 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2746 "Tahoma","Times New Roman", /* FIXME unverified */
2747 "Fixedsys,162", "System,162",
2748 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2749 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2750 { "Arial Tur,0", "Arial,162" },
2751 { "Courier New Tur,0", "Courier New,162" },
2752 { "Times New Roman Tur,0", "Times New Roman,162" }
2755 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2756 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2757 "Tahoma","Times New Roman", /* FIXME unverified */
2758 "Fixedsys,177", "System,177",
2759 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2760 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2764 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2765 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2766 "Tahoma","Times New Roman", /* FIXME unverified */
2767 "Fixedsys,178", "System,178",
2768 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2769 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2773 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2774 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2775 "Tahoma","Times New Roman", /* FIXME unverified */
2776 "Fixedsys,186", "System,186",
2777 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2778 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2779 { "Arial Baltic,0", "Arial,186" },
2780 { "Courier New Baltic,0", "Courier New,186" },
2781 { "Times New Roman Baltic,0", "Times New Roman,186" }
2784 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2785 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2786 "Tahoma","Times New Roman", /* FIXME unverified */
2787 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2791 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2792 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2793 "Tahoma","Times New Roman", /* FIXME unverified */
2794 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2798 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2799 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2800 "MS UI Gothic","MS Serif",
2801 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2804 /* Chinese Simplified */
2805 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2806 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2807 "SimSun", "NSimSun",
2808 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2812 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2813 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2815 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2818 /* Chinese Traditional */
2819 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2820 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2821 "PMingLiU", "MingLiU",
2822 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2827 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2829 return ( ansi_cp == 932 /* CP932 for Japanese */
2830 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2831 || ansi_cp == 949 /* CP949 for Korean */
2832 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2835 static inline HKEY create_fonts_NT_registry_key(void)
2839 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2840 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2844 static inline HKEY create_fonts_9x_registry_key(void)
2848 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2849 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2853 static inline HKEY create_config_fonts_registry_key(void)
2857 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2858 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2862 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2864 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2865 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2866 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2867 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2870 static void set_value_key(HKEY hkey, const char *name, const char *value)
2873 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2875 RegDeleteValueA(hkey, name);
2878 static void update_font_info(void)
2880 char buf[40], cpbuf[40];
2883 UINT i, ansi_cp = 0, oem_cp = 0;
2886 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2889 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2890 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2891 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2892 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2893 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2895 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2896 if (is_dbcs_ansi_cp(ansi_cp))
2897 use_default_fallback = TRUE;
2900 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2902 if (!strcmp( buf, cpbuf )) /* already set correctly */
2907 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2909 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2911 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2914 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2918 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2919 nls_update_font_list[i].oem_cp == oem_cp)
2921 hkey = create_config_fonts_registry_key();
2922 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2923 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2924 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2927 hkey = create_fonts_NT_registry_key();
2928 add_font_list(hkey, &nls_update_font_list[i]);
2931 hkey = create_fonts_9x_registry_key();
2932 add_font_list(hkey, &nls_update_font_list[i]);
2935 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2937 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2938 strlen(nls_update_font_list[i].shelldlg)+1);
2939 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2940 strlen(nls_update_font_list[i].tmsrmn)+1);
2942 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2943 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2944 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2945 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2946 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2947 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2948 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2949 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2951 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2952 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2953 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2961 /* Delete the FontSubstitutes from other locales */
2962 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2964 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2965 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2966 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2972 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2975 static BOOL init_freetype(void)
2977 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2980 "Wine cannot find the FreeType font library. To enable Wine to\n"
2981 "use TrueType fonts please install a version of FreeType greater than\n"
2982 "or equal to 2.0.5.\n"
2983 "http://www.freetype.org\n");
2987 #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;}
2989 LOAD_FUNCPTR(FT_Done_Face)
2990 LOAD_FUNCPTR(FT_Get_Char_Index)
2991 LOAD_FUNCPTR(FT_Get_First_Char)
2992 LOAD_FUNCPTR(FT_Get_Module)
2993 LOAD_FUNCPTR(FT_Get_Next_Char)
2994 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2995 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2996 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2997 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2998 LOAD_FUNCPTR(FT_Init_FreeType)
2999 LOAD_FUNCPTR(FT_Library_Version)
3000 LOAD_FUNCPTR(FT_Load_Glyph)
3001 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3002 LOAD_FUNCPTR(FT_Matrix_Multiply)
3003 #ifndef FT_MULFIX_INLINED
3004 LOAD_FUNCPTR(FT_MulFix)
3006 LOAD_FUNCPTR(FT_New_Face)
3007 LOAD_FUNCPTR(FT_New_Memory_Face)
3008 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3009 LOAD_FUNCPTR(FT_Outline_Transform)
3010 LOAD_FUNCPTR(FT_Outline_Translate)
3011 LOAD_FUNCPTR(FT_Render_Glyph)
3012 LOAD_FUNCPTR(FT_Select_Charmap)
3013 LOAD_FUNCPTR(FT_Set_Charmap)
3014 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3015 LOAD_FUNCPTR(FT_Vector_Transform)
3016 LOAD_FUNCPTR(FT_Vector_Unit)
3018 /* Don't warn if these ones are missing */
3019 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3020 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3021 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3024 if(pFT_Init_FreeType(&library) != 0) {
3025 ERR("Can't init FreeType library\n");
3026 wine_dlclose(ft_handle, NULL, 0);
3030 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3032 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3033 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3034 ((FT_Version.minor << 8) & 0x00ff00) |
3035 ((FT_Version.patch ) & 0x0000ff);
3037 font_driver = &freetype_funcs;
3042 "Wine cannot find certain functions that it needs inside the FreeType\n"
3043 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3044 "FreeType to at least version 2.1.4.\n"
3045 "http://www.freetype.org\n");
3046 wine_dlclose(ft_handle, NULL, 0);
3051 static void init_font_list(void)
3053 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3054 static const WCHAR pathW[] = {'P','a','t','h',0};
3056 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3057 WCHAR windowsdir[MAX_PATH];
3060 const char *data_dir;
3062 delete_external_font_keys();
3064 /* load the system bitmap fonts */
3065 load_system_fonts();
3067 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3068 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3069 strcatW(windowsdir, fontsW);
3070 if((unixname = wine_get_unix_file_name(windowsdir)))
3072 ReadFontDir(unixname, FALSE);
3073 HeapFree(GetProcessHeap(), 0, unixname);
3076 /* load the system truetype fonts */
3077 data_dir = wine_get_data_dir();
3078 if (!data_dir) data_dir = wine_get_build_dir();
3079 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3081 strcpy(unixname, data_dir);
3082 strcat(unixname, "/fonts/");
3083 ReadFontDir(unixname, TRUE);
3084 HeapFree(GetProcessHeap(), 0, unixname);
3087 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3088 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3089 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3091 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3092 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3093 &hkey) == ERROR_SUCCESS)
3095 LPWSTR data, valueW;
3096 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3097 &valuelen, &datalen, NULL, NULL);
3099 valuelen++; /* returned value doesn't include room for '\0' */
3100 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3101 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3104 dlen = datalen * sizeof(WCHAR);
3106 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3107 &dlen) == ERROR_SUCCESS)
3109 if(data[0] && (data[1] == ':'))
3111 if((unixname = wine_get_unix_file_name(data)))
3113 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3114 HeapFree(GetProcessHeap(), 0, unixname);
3117 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3119 WCHAR pathW[MAX_PATH];
3120 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3123 sprintfW(pathW, fmtW, windowsdir, data);
3124 if((unixname = wine_get_unix_file_name(pathW)))
3126 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3127 HeapFree(GetProcessHeap(), 0, unixname);
3130 load_font_from_data_dir(data);
3132 /* reset dlen and vlen */
3137 HeapFree(GetProcessHeap(), 0, data);
3138 HeapFree(GetProcessHeap(), 0, valueW);
3142 load_fontconfig_fonts();
3144 /* then look in any directories that we've specified in the config file */
3145 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3146 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3152 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3154 len += sizeof(WCHAR);
3155 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3156 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3158 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3159 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3160 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3161 TRACE( "got font path %s\n", debugstr_a(valueA) );
3165 LPSTR next = strchr( ptr, ':' );
3166 if (next) *next++ = 0;
3167 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3168 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3170 strcpy( unixname, home );
3171 strcat( unixname, ptr + 1 );
3172 ReadFontDir( unixname, TRUE );
3173 HeapFree( GetProcessHeap(), 0, unixname );
3176 ReadFontDir( ptr, TRUE );
3179 HeapFree( GetProcessHeap(), 0, valueA );
3181 HeapFree( GetProcessHeap(), 0, valueW );
3187 /* Mac default font locations. */
3188 ReadFontDir( "/Library/Fonts", TRUE );
3189 ReadFontDir( "/Network/Library/Fonts", TRUE );
3190 ReadFontDir( "/System/Library/Fonts", TRUE );
3191 if ((home = getenv( "HOME" )))
3193 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3194 strcpy( unixname, home );
3195 strcat( unixname, "/Library/Fonts" );
3196 ReadFontDir( unixname, TRUE);
3197 HeapFree( GetProcessHeap(), 0, unixname );
3202 static BOOL move_to_front(const WCHAR *name)
3204 Family *family, *cursor2;
3205 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3207 if(!strcmpiW(family->FamilyName, name))
3209 list_remove(&family->entry);
3210 list_add_head(&font_list, &family->entry);
3217 static BOOL set_default(const WCHAR **name_list)
3221 if (move_to_front(*name_list)) return TRUE;
3228 static void reorder_font_list(void)
3230 set_default( default_serif_list );
3231 set_default( default_fixed_list );
3232 set_default( default_sans_list );
3235 /*************************************************************
3238 * Initialize FreeType library and create a list of available faces
3240 BOOL WineEngInit(void)
3242 HKEY hkey_font_cache;
3246 /* update locale dependent font info in registry */
3249 if(!init_freetype()) return FALSE;
3251 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3253 ERR("Failed to create font mutex\n");
3256 WaitForSingleObject(font_mutex, INFINITE);
3258 create_font_cache_key(&hkey_font_cache, &disposition);
3260 if(disposition == REG_CREATED_NEW_KEY)
3263 load_font_list_from_cache(hkey_font_cache);
3265 RegCloseKey(hkey_font_cache);
3267 reorder_font_list();
3274 if(disposition == REG_CREATED_NEW_KEY)
3275 update_reg_entries();
3277 init_system_links();
3279 ReleaseMutex(font_mutex);
3284 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3287 TT_HoriHeader *pHori;
3291 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3292 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3294 if(height == 0) height = 16;
3296 /* Calc. height of EM square:
3298 * For +ve lfHeight we have
3299 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3300 * Re-arranging gives:
3301 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3303 * For -ve lfHeight we have
3305 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3306 * with il = winAscent + winDescent - units_per_em]
3311 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3312 ppem = MulDiv(ft_face->units_per_EM, height,
3313 pHori->Ascender - pHori->Descender);
3315 ppem = MulDiv(ft_face->units_per_EM, height,
3316 pOS2->usWinAscent + pOS2->usWinDescent);
3324 static struct font_mapping *map_font_file( const char *name )
3326 struct font_mapping *mapping;
3330 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3331 if (fstat( fd, &st ) == -1) goto error;
3333 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3335 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3337 mapping->refcount++;
3342 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3345 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3348 if (mapping->data == MAP_FAILED)
3350 HeapFree( GetProcessHeap(), 0, mapping );
3353 mapping->refcount = 1;
3354 mapping->dev = st.st_dev;
3355 mapping->ino = st.st_ino;
3356 mapping->size = st.st_size;
3357 list_add_tail( &mappings_list, &mapping->entry );
3365 static void unmap_font_file( struct font_mapping *mapping )
3367 if (!--mapping->refcount)
3369 list_remove( &mapping->entry );
3370 munmap( mapping->data, mapping->size );
3371 HeapFree( GetProcessHeap(), 0, mapping );
3375 static LONG load_VDMX(GdiFont*, LONG);
3377 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3384 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3388 if (!(font->mapping = map_font_file( face->file )))
3390 WARN("failed to map %s\n", debugstr_a(face->file));
3393 data_ptr = font->mapping->data;
3394 data_size = font->mapping->size;
3398 data_ptr = face->font_data_ptr;
3399 data_size = face->font_data_size;
3402 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3404 ERR("FT_New_Face rets %d\n", err);
3408 /* set it here, as load_VDMX needs it */
3409 font->ft_face = ft_face;
3411 if(FT_IS_SCALABLE(ft_face)) {
3412 /* load the VDMX table if we have one */
3413 font->ppem = load_VDMX(font, height);
3415 font->ppem = calc_ppem_for_height(ft_face, height);
3416 TRACE("height %d => ppem %d\n", height, font->ppem);
3418 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3419 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3421 font->ppem = height;
3422 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3423 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3429 static int get_nearest_charset(Face *face, int *cp)
3431 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3432 a single face with the requested charset. The idea is to check if
3433 the selected font supports the current ANSI codepage, if it does
3434 return the corresponding charset, else return the first charset */
3437 int acp = GetACP(), i;
3441 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3442 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3443 return csi.ciCharset;
3445 for(i = 0; i < 32; i++) {
3447 if(face->fs.fsCsb[0] & fs0) {
3448 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3450 return csi.ciCharset;
3453 FIXME("TCI failing on %x\n", fs0);
3457 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3458 face->fs.fsCsb[0], face->file);
3460 return DEFAULT_CHARSET;
3463 static GdiFont *alloc_font(void)
3465 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3467 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3468 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3470 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3471 ret->total_kern_pairs = (DWORD)-1;
3472 ret->kern_pairs = NULL;
3473 list_init(&ret->hfontlist);
3474 list_init(&ret->child_fonts);
3478 static void free_font(GdiFont *font)
3480 struct list *cursor, *cursor2;
3483 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3485 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3486 list_remove(cursor);
3488 free_font(child->font);
3489 HeapFree(GetProcessHeap(), 0, child);
3492 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3494 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3495 DeleteObject(hfontlist->hfont);
3496 list_remove(&hfontlist->entry);
3497 HeapFree(GetProcessHeap(), 0, hfontlist);
3500 if (font->ft_face) pFT_Done_Face(font->ft_face);
3501 if (font->mapping) unmap_font_file( font->mapping );
3502 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3503 HeapFree(GetProcessHeap(), 0, font->potm);
3504 HeapFree(GetProcessHeap(), 0, font->name);
3505 for (i = 0; i < font->gmsize; i++)
3506 HeapFree(GetProcessHeap(),0,font->gm[i]);
3507 HeapFree(GetProcessHeap(), 0, font->gm);
3508 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3509 HeapFree(GetProcessHeap(), 0, font);
3513 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3515 FT_Face ft_face = font->ft_face;
3519 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3526 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3528 /* make sure value of len is the value freetype says it needs */
3531 FT_ULong needed = 0;
3532 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3533 if( !err && needed < len) len = needed;
3535 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3538 TRACE("Can't find table %c%c%c%c\n",
3539 /* bytes were reversed */
3540 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3541 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3547 /*************************************************************
3550 * load the vdmx entry for the specified height
3553 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3554 ( ( (FT_ULong)_x4 << 24 ) | \
3555 ( (FT_ULong)_x3 << 16 ) | \
3556 ( (FT_ULong)_x2 << 8 ) | \
3559 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3574 static LONG load_VDMX(GdiFont *font, LONG height)
3578 BYTE devXRatio, devYRatio;
3579 USHORT numRecs, numRatios;
3580 DWORD result, offset = -1;
3584 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3586 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3589 /* FIXME: need the real device aspect ratio */
3593 numRecs = GET_BE_WORD(hdr[1]);
3594 numRatios = GET_BE_WORD(hdr[2]);
3596 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3597 for(i = 0; i < numRatios; i++) {
3600 offset = (3 * 2) + (i * sizeof(Ratios));
3601 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3604 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3606 if((ratio.xRatio == 0 &&
3607 ratio.yStartRatio == 0 &&
3608 ratio.yEndRatio == 0) ||
3609 (devXRatio == ratio.xRatio &&
3610 devYRatio >= ratio.yStartRatio &&
3611 devYRatio <= ratio.yEndRatio))
3613 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3614 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3615 offset = GET_BE_WORD(tmp);
3621 FIXME("No suitable ratio found\n");
3625 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3627 BYTE startsz, endsz;
3630 recs = GET_BE_WORD(group.recs);
3631 startsz = group.startsz;
3632 endsz = group.endsz;
3634 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3636 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3637 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3638 if(result == GDI_ERROR) {
3639 FIXME("Failed to retrieve vTable\n");
3644 for(i = 0; i < recs; i++) {
3645 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3646 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3647 ppem = GET_BE_WORD(vTable[i * 3]);
3649 if(yMax + -yMin == height) {
3652 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3655 if(yMax + -yMin > height) {
3658 goto end; /* failed */
3660 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3661 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3662 ppem = GET_BE_WORD(vTable[i * 3]);
3663 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3669 TRACE("ppem not found for height %d\n", height);
3673 HeapFree(GetProcessHeap(), 0, vTable);
3679 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3681 if(font->font_desc.hash != fd->hash) return TRUE;
3682 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3683 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3684 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3685 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3688 static void calc_hash(FONT_DESC *pfd)
3690 DWORD hash = 0, *ptr, two_chars;
3694 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3696 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3698 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3700 pwc = (WCHAR *)&two_chars;
3702 *pwc = toupperW(*pwc);
3704 *pwc = toupperW(*pwc);
3708 hash ^= !pfd->can_use_bitmap;
3713 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3718 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3722 fd.can_use_bitmap = can_use_bitmap;
3725 /* try the child list */
3726 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3727 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3728 if(!fontcmp(ret, &fd)) {
3729 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3730 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3731 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3732 if(hflist->hfont == hfont)
3738 /* try the in-use list */
3739 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3740 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3741 if(!fontcmp(ret, &fd)) {
3742 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3743 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3744 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3745 if(hflist->hfont == hfont)
3748 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3749 hflist->hfont = hfont;
3750 list_add_head(&ret->hfontlist, &hflist->entry);
3755 /* then the unused list */
3756 font_elem_ptr = list_head(&unused_gdi_font_list);
3757 while(font_elem_ptr) {
3758 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3759 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3760 if(!fontcmp(ret, &fd)) {
3761 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3762 assert(list_empty(&ret->hfontlist));
3763 TRACE("Found %p in unused list\n", ret);
3764 list_remove(&ret->entry);
3765 list_add_head(&gdi_font_list, &ret->entry);
3766 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3767 hflist->hfont = hfont;
3768 list_add_head(&ret->hfontlist, &hflist->entry);
3775 static void add_to_cache(GdiFont *font)
3777 static DWORD cache_num = 1;
3779 font->cache_num = cache_num++;
3780 list_add_head(&gdi_font_list, &font->entry);
3783 /*************************************************************
3784 * create_child_font_list
3786 static BOOL create_child_font_list(GdiFont *font)
3789 SYSTEM_LINKS *font_link;
3790 CHILD_FONT *font_link_entry, *new_child;
3794 psub = get_font_subst(&font_subst_list, font->name, -1);
3795 font_name = psub ? psub->to.name : font->name;
3796 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3798 if(!strcmpiW(font_link->font_name, font_name))
3800 TRACE("found entry in system list\n");
3801 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3803 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3804 new_child->face = font_link_entry->face;
3805 new_child->font = NULL;
3806 list_add_tail(&font->child_fonts, &new_child->entry);
3807 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3814 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3815 * Sans Serif. This is how asian windows get default fallbacks for fonts
3817 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3818 font->charset != OEM_CHARSET &&
3819 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3820 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3822 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3824 TRACE("found entry in default fallback list\n");
3825 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3827 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3828 new_child->face = font_link_entry->face;
3829 new_child->font = NULL;
3830 list_add_tail(&font->child_fonts, &new_child->entry);
3831 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3841 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3843 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3845 if (pFT_Set_Charmap)
3848 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3850 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3852 for (i = 0; i < ft_face->num_charmaps; i++)
3854 if (ft_face->charmaps[i]->encoding == encoding)
3856 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3857 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3859 switch (ft_face->charmaps[i]->platform_id)
3862 cmap_def = ft_face->charmaps[i];
3864 case 0: /* Apple Unicode */
3865 cmap0 = ft_face->charmaps[i];
3867 case 1: /* Macintosh */
3868 cmap1 = ft_face->charmaps[i];
3871 cmap2 = ft_face->charmaps[i];
3873 case 3: /* Microsoft */
3874 cmap3 = ft_face->charmaps[i];
3879 if (cmap3) /* prefer Microsoft cmap table */
3880 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3882 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3884 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3886 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3888 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3890 return ft_err == FT_Err_Ok;
3893 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3897 /*************************************************************
3900 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3901 LPCWSTR output, const DEVMODEW *devmode )
3903 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3905 if (!physdev) return FALSE;
3906 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3911 /*************************************************************
3914 static BOOL freetype_DeleteDC( PHYSDEV dev )
3916 struct freetype_physdev *physdev = get_freetype_dev( dev );
3917 HeapFree( GetProcessHeap(), 0, physdev );
3922 /*************************************************************
3923 * freetype_SelectFont
3925 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3927 struct freetype_physdev *physdev = get_freetype_dev( dev );
3929 Face *face, *best, *best_bitmap;
3930 Family *family, *last_resort_family;
3931 struct list *family_elem_ptr, *face_elem_ptr;
3932 INT height, width = 0;
3933 unsigned int score = 0, new_score;
3934 signed int diff = 0, newdiff;
3935 BOOL bd, it, can_use_bitmap, want_vertical;
3940 FontSubst *psub = NULL;
3941 DC *dc = get_dc_ptr( dev->hdc );
3943 if (!hfont) /* notification that the font has been changed by another driver */
3946 physdev->font = NULL;
3947 release_dc_ptr( dc );
3951 GetObjectW( hfont, sizeof(lf), &lf );
3952 lf.lfWidth = abs(lf.lfWidth);
3954 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3956 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3957 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3958 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3961 if(dc->GraphicsMode == GM_ADVANCED)
3963 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3964 /* Try to avoid not necessary glyph transformations */
3965 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3967 lf.lfHeight *= fabs(dcmat.eM11);
3968 lf.lfWidth *= fabs(dcmat.eM11);
3969 dcmat.eM11 = dcmat.eM22 = 1.0;
3974 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3975 font scaling abilities. */
3976 dcmat.eM11 = dcmat.eM22 = 1.0;
3977 dcmat.eM21 = dcmat.eM12 = 0;
3978 if (dc->vport2WorldValid)
3980 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3981 lf.lfOrientation = -lf.lfOrientation;
3982 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3983 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3987 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3988 dcmat.eM21, dcmat.eM22);
3991 EnterCriticalSection( &freetype_cs );
3993 /* check the cache first */
3994 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3995 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3999 if(list_empty(&font_list)) /* No fonts installed */
4001 TRACE("No fonts installed\n");
4005 TRACE("not in cache\n");
4008 ret->font_desc.matrix = dcmat;
4009 ret->font_desc.lf = lf;
4010 ret->font_desc.can_use_bitmap = can_use_bitmap;
4011 calc_hash(&ret->font_desc);
4012 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4013 hflist->hfont = hfont;
4014 list_add_head(&ret->hfontlist, &hflist->entry);
4016 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4017 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4018 original value lfCharSet. Note this is a special case for
4019 Symbol and doesn't happen at least for "Wingdings*" */
4021 if(!strcmpiW(lf.lfFaceName, SymbolW))
4022 lf.lfCharSet = SYMBOL_CHARSET;
4024 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4025 switch(lf.lfCharSet) {
4026 case DEFAULT_CHARSET:
4027 csi.fs.fsCsb[0] = 0;
4030 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4031 csi.fs.fsCsb[0] = 0;
4037 if(lf.lfFaceName[0] != '\0') {
4038 SYSTEM_LINKS *font_link;
4039 CHILD_FONT *font_link_entry;
4040 LPWSTR FaceName = lf.lfFaceName;
4042 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4045 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4046 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4047 if (psub->to.charset != -1)
4048 lf.lfCharSet = psub->to.charset;
4051 /* We want a match on name and charset or just name if
4052 charset was DEFAULT_CHARSET. If the latter then
4053 we fixup the returned charset later in get_nearest_charset
4054 where we'll either use the charset of the current ansi codepage
4055 or if that's unavailable the first charset that the font supports.
4057 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4058 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4059 if (!strcmpiW(family->FamilyName, FaceName) ||
4060 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4062 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4063 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4064 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4065 if(face->scalable || can_use_bitmap)
4071 /* Search by full face name. */
4072 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4073 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4074 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4075 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4076 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4077 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
4079 if(face->scalable || can_use_bitmap)
4086 * Try check the SystemLink list first for a replacement font.
4087 * We may find good replacements there.
4089 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4091 if(!strcmpiW(font_link->font_name, FaceName) ||
4092 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4094 TRACE("found entry in system list\n");
4095 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4097 face = font_link_entry->face;
4098 family = face->family;
4099 if(csi.fs.fsCsb[0] &
4100 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4102 if(face->scalable || can_use_bitmap)
4110 psub = NULL; /* substitution is no more relevant */
4112 /* If requested charset was DEFAULT_CHARSET then try using charset
4113 corresponding to the current ansi codepage */
4114 if (!csi.fs.fsCsb[0])
4117 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4118 FIXME("TCI failed on codepage %d\n", acp);
4119 csi.fs.fsCsb[0] = 0;
4121 lf.lfCharSet = csi.ciCharset;
4124 want_vertical = (lf.lfFaceName[0] == '@');
4126 /* Face families are in the top 4 bits of lfPitchAndFamily,
4127 so mask with 0xF0 before testing */
4129 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4130 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4131 strcpyW(lf.lfFaceName, defFixed);
4132 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4133 strcpyW(lf.lfFaceName, defSerif);
4134 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4135 strcpyW(lf.lfFaceName, defSans);
4137 strcpyW(lf.lfFaceName, defSans);
4138 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4139 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4140 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4141 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4142 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4143 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4144 if(face->scalable || can_use_bitmap)
4150 last_resort_family = NULL;
4151 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4152 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4153 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4154 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4155 if(face->vertical == want_vertical &&
4156 (csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))) {
4159 if(can_use_bitmap && !last_resort_family)
4160 last_resort_family = family;
4165 if(last_resort_family) {
4166 family = last_resort_family;
4167 csi.fs.fsCsb[0] = 0;
4171 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4172 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4173 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4174 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4175 if(face->scalable && face->vertical == want_vertical) {
4176 csi.fs.fsCsb[0] = 0;
4177 WARN("just using first face for now\n");
4180 if(can_use_bitmap && !last_resort_family)
4181 last_resort_family = family;
4184 if(!last_resort_family) {
4185 FIXME("can't find a single appropriate font - bailing\n");
4191 WARN("could only find a bitmap font - this will probably look awful!\n");
4192 family = last_resort_family;
4193 csi.fs.fsCsb[0] = 0;
4196 it = lf.lfItalic ? 1 : 0;
4197 bd = lf.lfWeight > 550 ? 1 : 0;
4199 height = lf.lfHeight;
4201 face = best = best_bitmap = NULL;
4202 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4204 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4208 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4209 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4210 new_score = (italic ^ it) + (bold ^ bd);
4211 if(!best || new_score <= score)
4213 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4214 italic, bold, it, bd);
4217 if(best->scalable && score == 0) break;
4221 newdiff = height - (signed int)(best->size.height);
4223 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4224 if(!best_bitmap || new_score < score ||
4225 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4227 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4230 if(score == 0 && diff == 0) break;
4237 face = best->scalable ? best : best_bitmap;
4238 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4239 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4242 height = lf.lfHeight;
4246 if(csi.fs.fsCsb[0]) {
4247 ret->charset = lf.lfCharSet;
4248 ret->codepage = csi.ciACP;
4251 ret->charset = get_nearest_charset(face, &ret->codepage);
4253 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4254 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4256 ret->aveWidth = height ? lf.lfWidth : 0;
4258 if(!face->scalable) {
4259 /* Windows uses integer scaling factors for bitmap fonts */
4260 INT scale, scaled_height;
4261 GdiFont *cachedfont;
4263 /* FIXME: rotation of bitmap fonts is ignored */
4264 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4266 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4267 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4268 dcmat.eM11 = dcmat.eM22 = 1.0;
4269 /* As we changed the matrix, we need to search the cache for the font again,
4270 * otherwise we might explode the cache. */
4271 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4272 TRACE("Found cached font after non-scalable matrix rescale!\n");
4277 calc_hash(&ret->font_desc);
4279 if (height != 0) height = diff;
4280 height += face->size.height;
4282 scale = (height + face->size.height - 1) / face->size.height;
4283 scaled_height = scale * face->size.height;
4284 /* Only jump to the next height if the difference <= 25% original height */
4285 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4286 /* The jump between unscaled and doubled is delayed by 1 */
4287 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4288 ret->scale_y = scale;
4290 width = face->size.x_ppem >> 6;
4291 height = face->size.y_ppem >> 6;
4295 TRACE("font scale y: %f\n", ret->scale_y);
4297 ret->ft_face = OpenFontFace(ret, face, width, height);
4306 ret->ntmFlags = face->ntmFlags;
4308 if (ret->charset == SYMBOL_CHARSET &&
4309 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4312 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4316 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4319 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4320 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4321 ret->underline = lf.lfUnderline ? 0xff : 0;
4322 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4323 create_child_font_list(ret);
4325 if (face->vertical) /* We need to try to load the GSUB table */
4327 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4328 if (length != GDI_ERROR)
4330 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4331 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4332 TRACE("Loaded GSUB table of %i bytes\n",length);
4336 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4343 physdev->font = ret;
4345 LeaveCriticalSection( &freetype_cs );
4346 release_dc_ptr( dc );
4347 return ret ? hfont : 0;
4350 static void dump_gdi_font_list(void)
4353 struct list *elem_ptr;
4355 TRACE("---------- gdiFont Cache ----------\n");
4356 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4357 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4358 TRACE("gdiFont=%p %s %d\n",
4359 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4362 TRACE("---------- Unused gdiFont Cache ----------\n");
4363 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4364 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4365 TRACE("gdiFont=%p %s %d\n",
4366 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4369 TRACE("---------- Child gdiFont Cache ----------\n");
4370 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4371 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4372 TRACE("gdiFont=%p %s %d\n",
4373 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4377 /*************************************************************
4378 * WineEngDestroyFontInstance
4380 * free the gdiFont associated with this handle
4383 BOOL WineEngDestroyFontInstance(HFONT handle)
4388 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4392 EnterCriticalSection( &freetype_cs );
4394 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4396 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4397 while(hfontlist_elem_ptr) {
4398 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4399 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4400 if(hflist->hfont == handle) {
4401 TRACE("removing child font %p from child list\n", gdiFont);
4402 list_remove(&gdiFont->entry);
4403 LeaveCriticalSection( &freetype_cs );
4409 TRACE("destroying hfont=%p\n", handle);
4411 dump_gdi_font_list();
4413 font_elem_ptr = list_head(&gdi_font_list);
4414 while(font_elem_ptr) {
4415 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4416 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4418 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4419 while(hfontlist_elem_ptr) {
4420 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4421 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4422 if(hflist->hfont == handle) {
4423 list_remove(&hflist->entry);
4424 HeapFree(GetProcessHeap(), 0, hflist);
4428 if(list_empty(&gdiFont->hfontlist)) {
4429 TRACE("Moving to Unused list\n");
4430 list_remove(&gdiFont->entry);
4431 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4436 font_elem_ptr = list_head(&unused_gdi_font_list);
4437 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4438 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4439 while(font_elem_ptr) {
4440 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4441 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4442 TRACE("freeing %p\n", gdiFont);
4443 list_remove(&gdiFont->entry);
4446 LeaveCriticalSection( &freetype_cs );
4450 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4457 id += IDS_FIRST_SCRIPT;
4458 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4459 if (!rsrc) return 0;
4460 hMem = LoadResource( gdi32_module, rsrc );
4461 if (!hMem) return 0;
4463 p = LockResource( hMem );
4465 while (id--) p += *p + 1;
4467 i = min(LF_FACESIZE - 1, *p);
4468 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4474 /***************************************************
4475 * create_enum_charset_list
4477 * This function creates charset enumeration list because in DEFAULT_CHARSET
4478 * case, the ANSI codepage's charset takes precedence over other charsets.
4479 * This function works as a filter other than DEFAULT_CHARSET case.
4481 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4486 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4487 csi.fs.fsCsb[0] != 0) {
4488 list->element[n].mask = csi.fs.fsCsb[0];
4489 list->element[n].charset = csi.ciCharset;
4490 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4493 else { /* charset is DEFAULT_CHARSET or invalid. */
4496 /* Set the current codepage's charset as the first element. */
4498 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4499 csi.fs.fsCsb[0] != 0) {
4500 list->element[n].mask = csi.fs.fsCsb[0];
4501 list->element[n].charset = csi.ciCharset;
4502 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4506 /* Fill out left elements. */
4507 for (i = 0; i < 32; i++) {
4509 fs.fsCsb[0] = 1L << i;
4511 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4512 continue; /* skip, already added. */
4513 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4514 continue; /* skip, this is an invalid fsCsb bit. */
4516 list->element[n].mask = fs.fsCsb[0];
4517 list->element[n].charset = csi.ciCharset;
4518 load_script_name( i, list->element[n].name );
4527 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4528 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4533 if (face->cached_enum_data)
4536 *pelf = face->cached_enum_data->elf;
4537 *pntm = face->cached_enum_data->ntm;
4538 *ptype = face->cached_enum_data->type;
4542 font = alloc_font();
4544 if(face->scalable) {
4545 height = -2048; /* 2048 is the most common em size */
4548 height = face->size.y_ppem >> 6;
4549 width = face->size.x_ppem >> 6;
4551 font->scale_y = 1.0;
4553 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4559 font->name = strdupW(face->family->FamilyName);
4560 font->ntmFlags = face->ntmFlags;
4562 if (get_outline_text_metrics(font))
4564 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4566 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4568 lstrcpynW(pelf->elfLogFont.lfFaceName,
4569 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4571 lstrcpynW(pelf->elfFullName,
4572 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4574 lstrcpynW(pelf->elfStyle,
4575 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4580 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4582 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4584 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4586 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4588 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4589 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4592 pntm->ntmTm.ntmFlags = face->ntmFlags;
4593 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4594 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4595 pntm->ntmFontSig = face->fs;
4597 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4599 pelf->elfLogFont.lfEscapement = 0;
4600 pelf->elfLogFont.lfOrientation = 0;
4601 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4602 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4603 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4604 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4605 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4606 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4607 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4608 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4609 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4610 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4611 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4614 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4615 *ptype |= TRUETYPE_FONTTYPE;
4616 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4617 *ptype |= DEVICE_FONTTYPE;
4618 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4619 *ptype |= RASTER_FONTTYPE;
4621 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4622 if (face->cached_enum_data)
4624 face->cached_enum_data->elf = *pelf;
4625 face->cached_enum_data->ntm = *pntm;
4626 face->cached_enum_data->type = *ptype;
4632 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4634 struct list *face_elem_ptr;
4636 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4638 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4640 static const WCHAR spaceW[] = { ' ',0 };
4641 WCHAR full_family_name[LF_FULLFACESIZE];
4642 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4644 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4646 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4647 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4651 strcpyW(full_family_name, family->FamilyName);
4652 strcatW(full_family_name, spaceW);
4653 strcatW(full_family_name, face->StyleName);
4654 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4660 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4662 static const WCHAR spaceW[] = { ' ',0 };
4663 WCHAR full_family_name[LF_FULLFACESIZE];
4665 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4667 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4669 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4670 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4674 strcpyW(full_family_name, face->family->FamilyName);
4675 strcatW(full_family_name, spaceW);
4676 strcatW(full_family_name, face->StyleName);
4677 return !strcmpiW(lf->lfFaceName, full_family_name);
4680 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4681 FONTENUMPROCW proc, LPARAM lparam)
4684 NEWTEXTMETRICEXW ntm;
4688 GetEnumStructs(face, &elf, &ntm, &type);
4689 for(i = 0; i < list->total; i++) {
4690 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4691 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4692 load_script_name( IDS_OEM_DOS, elf.elfScript );
4693 i = list->total; /* break out of loop after enumeration */
4694 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4697 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4698 strcpyW(elf.elfScript, list->element[i].name);
4699 if (!elf.elfScript[0])
4700 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4702 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4703 debugstr_w(elf.elfLogFont.lfFaceName),
4704 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4705 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4706 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4707 ntm.ntmTm.ntmFlags);
4708 /* release section before callback (FIXME) */
4709 LeaveCriticalSection( &freetype_cs );
4710 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4711 EnterCriticalSection( &freetype_cs );
4716 /*************************************************************
4717 * freetype_EnumFonts
4719 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4723 struct list *family_elem_ptr, *face_elem_ptr;
4725 struct enum_charset_list enum_charsets;
4729 lf.lfCharSet = DEFAULT_CHARSET;
4730 lf.lfPitchAndFamily = 0;
4731 lf.lfFaceName[0] = 0;
4735 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4737 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4740 EnterCriticalSection( &freetype_cs );
4741 if(plf->lfFaceName[0]) {
4743 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4746 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4747 debugstr_w(psub->to.name));
4749 strcpyW(lf.lfFaceName, psub->to.name);
4753 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4754 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4755 if(family_matches(family, plf)) {
4756 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4757 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4758 if (!face_matches(face, plf)) continue;
4759 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4764 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4765 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4766 face_elem_ptr = list_head(&family->faces);
4767 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4768 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4771 LeaveCriticalSection( &freetype_cs );
4775 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4777 pt->x.value = vec->x >> 6;
4778 pt->x.fract = (vec->x & 0x3f) << 10;
4779 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4780 pt->y.value = vec->y >> 6;
4781 pt->y.fract = (vec->y & 0x3f) << 10;
4782 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4786 /***************************************************
4787 * According to the MSDN documentation on WideCharToMultiByte,
4788 * certain codepages cannot set the default_used parameter.
4789 * This returns TRUE if the codepage can set that parameter, false else
4790 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4792 static BOOL codepage_sets_default_used(UINT codepage)
4806 * GSUB Table handling functions
4809 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4811 const GSUB_CoverageFormat1* cf1;
4815 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4817 int count = GET_BE_WORD(cf1->GlyphCount);
4819 TRACE("Coverage Format 1, %i glyphs\n",count);
4820 for (i = 0; i < count; i++)
4821 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4825 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4827 const GSUB_CoverageFormat2* cf2;
4830 cf2 = (const GSUB_CoverageFormat2*)cf1;
4832 count = GET_BE_WORD(cf2->RangeCount);
4833 TRACE("Coverage Format 2, %i ranges\n",count);
4834 for (i = 0; i < count; i++)
4836 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4838 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4839 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4841 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4842 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4848 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4853 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4855 const GSUB_ScriptList *script;
4856 const GSUB_Script *deflt = NULL;
4858 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4860 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4861 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4863 const GSUB_Script *scr;
4866 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4867 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4869 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4871 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4877 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4881 const GSUB_LangSys *Lang;
4883 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4885 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4887 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4888 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4890 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4893 offset = GET_BE_WORD(script->DefaultLangSys);
4896 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4902 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4905 const GSUB_FeatureList *feature;
4906 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4908 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4909 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4911 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4912 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4914 const GSUB_Feature *feat;
4915 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4922 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4926 const GSUB_LookupList *lookup;
4927 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4929 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4930 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4932 const GSUB_LookupTable *look;
4933 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4934 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4935 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4936 if (GET_BE_WORD(look->LookupType) != 1)
4937 FIXME("We only handle SubType 1\n");
4942 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4944 const GSUB_SingleSubstFormat1 *ssf1;
4945 offset = GET_BE_WORD(look->SubTable[j]);
4946 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4947 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4949 int offset = GET_BE_WORD(ssf1->Coverage);
4950 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4951 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4953 TRACE(" Glyph 0x%x ->",glyph);
4954 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4955 TRACE(" 0x%x\n",glyph);
4960 const GSUB_SingleSubstFormat2 *ssf2;
4964 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4965 offset = GET_BE_WORD(ssf1->Coverage);
4966 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4967 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4968 TRACE(" Coverage index %i\n",index);
4971 TRACE(" Glyph is 0x%x ->",glyph);
4972 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4973 TRACE("0x%x\n",glyph);
4982 static const char* get_opentype_script(const GdiFont *font)
4985 * I am not sure if this is the correct way to generate our script tag
4988 switch (font->charset)
4990 case ANSI_CHARSET: return "latn";
4991 case BALTIC_CHARSET: return "latn"; /* ?? */
4992 case CHINESEBIG5_CHARSET: return "hani";
4993 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4994 case GB2312_CHARSET: return "hani";
4995 case GREEK_CHARSET: return "grek";
4996 case HANGUL_CHARSET: return "hang";
4997 case RUSSIAN_CHARSET: return "cyrl";
4998 case SHIFTJIS_CHARSET: return "kana";
4999 case TURKISH_CHARSET: return "latn"; /* ?? */
5000 case VIETNAMESE_CHARSET: return "latn";
5001 case JOHAB_CHARSET: return "latn"; /* ?? */
5002 case ARABIC_CHARSET: return "arab";
5003 case HEBREW_CHARSET: return "hebr";
5004 case THAI_CHARSET: return "thai";
5005 default: return "latn";
5009 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5011 const GSUB_Header *header;
5012 const GSUB_Script *script;
5013 const GSUB_LangSys *language;
5014 const GSUB_Feature *feature;
5016 if (!font->GSUB_Table)
5019 header = font->GSUB_Table;
5021 script = GSUB_get_script_table(header, get_opentype_script(font));
5024 TRACE("Script not found\n");
5027 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5030 TRACE("Language not found\n");
5033 feature = GSUB_get_feature(header, language, "vrt2");
5035 feature = GSUB_get_feature(header, language, "vert");
5038 TRACE("vrt2/vert feature not found\n");
5041 return GSUB_apply_feature(header, feature, glyph);
5044 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5048 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5049 WCHAR wc = (WCHAR)glyph;
5051 BOOL *default_used_pointer;
5054 default_used_pointer = NULL;
5055 default_used = FALSE;
5056 if (codepage_sets_default_used(font->codepage))
5057 default_used_pointer = &default_used;
5058 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5061 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5062 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5066 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5068 if (glyph < 0x100) glyph += 0xf000;
5069 /* there is a number of old pre-Unicode "broken" TTFs, which
5070 do have symbols at U+00XX instead of U+f0XX */
5071 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5072 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5074 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5079 /*************************************************************
5080 * freetype_GetGlyphIndices
5082 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5084 struct freetype_physdev *physdev = get_freetype_dev( dev );
5087 BOOL got_default = FALSE;
5091 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5092 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5095 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5097 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5102 EnterCriticalSection( &freetype_cs );
5104 for(i = 0; i < count; i++)
5106 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5111 if (FT_IS_SFNT(physdev->font->ft_face))
5113 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5114 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5119 get_text_metrics(physdev->font, &textm);
5120 default_char = textm.tmDefaultChar;
5124 pgi[i] = default_char;
5127 LeaveCriticalSection( &freetype_cs );
5131 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5133 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5134 return !memcmp(matrix, &identity, sizeof(FMAT2));
5137 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5139 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5140 return !memcmp(matrix, &identity, sizeof(MAT2));
5143 static inline BYTE get_max_level( UINT format )
5147 case GGO_GRAY2_BITMAP: return 4;
5148 case GGO_GRAY4_BITMAP: return 16;
5149 case GGO_GRAY8_BITMAP: return 64;
5154 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5156 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5157 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5160 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5161 FT_Face ft_face = incoming_font->ft_face;
5162 GdiFont *font = incoming_font;
5163 FT_UInt glyph_index;
5164 DWORD width, height, pitch, needed = 0;
5165 FT_Bitmap ft_bitmap;
5167 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5169 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5170 double widthRatio = 1.0;
5171 FT_Matrix transMat = identityMat;
5172 FT_Matrix transMatUnrotated;
5173 BOOL needsTransform = FALSE;
5174 BOOL tategaki = (font->GSUB_Table != NULL);
5175 UINT original_index;
5177 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5178 buflen, buf, lpmat);
5180 TRACE("font transform %f %f %f %f\n",
5181 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5182 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5184 if(format & GGO_GLYPH_INDEX) {
5185 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5186 original_index = glyph;
5187 format &= ~GGO_GLYPH_INDEX;
5189 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5190 ft_face = font->ft_face;
5191 original_index = glyph_index;
5194 if(format & GGO_UNHINTED) {
5195 load_flags |= FT_LOAD_NO_HINTING;
5196 format &= ~GGO_UNHINTED;
5199 /* tategaki never appears to happen to lower glyph index */
5200 if (glyph_index < TATEGAKI_LOWER_BOUND )
5203 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5204 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5205 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5206 font->gmsize * sizeof(GM*));
5208 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5209 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5211 *lpgm = FONT_GM(font,original_index)->gm;
5212 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5213 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5214 lpgm->gmCellIncX, lpgm->gmCellIncY);
5215 return 1; /* FIXME */
5219 if (!font->gm[original_index / GM_BLOCK_SIZE])
5220 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5222 /* Scaling factor */
5227 get_text_metrics(font, &tm);
5229 widthRatio = (double)font->aveWidth;
5230 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5233 widthRatio = font->scale_y;
5235 /* Scaling transform */
5236 if (widthRatio != 1.0 || font->scale_y != 1.0)
5239 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5242 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5244 pFT_Matrix_Multiply(&scaleMat, &transMat);
5245 needsTransform = TRUE;
5248 /* Slant transform */
5249 if (font->fake_italic) {
5252 slantMat.xx = (1 << 16);
5253 slantMat.xy = ((1 << 16) >> 2);
5255 slantMat.yy = (1 << 16);
5256 pFT_Matrix_Multiply(&slantMat, &transMat);
5257 needsTransform = TRUE;
5260 /* Rotation transform */
5261 transMatUnrotated = transMat;
5262 if(font->orientation && !tategaki) {
5263 FT_Matrix rotationMat;
5265 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5266 pFT_Vector_Unit(&vecAngle, angle);
5267 rotationMat.xx = vecAngle.x;
5268 rotationMat.xy = -vecAngle.y;
5269 rotationMat.yx = -rotationMat.xy;
5270 rotationMat.yy = rotationMat.xx;
5272 pFT_Matrix_Multiply(&rotationMat, &transMat);
5273 needsTransform = TRUE;
5276 /* World transform */
5277 if (!is_identity_FMAT2(&font->font_desc.matrix))
5280 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5281 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5282 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5283 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5284 pFT_Matrix_Multiply(&worldMat, &transMat);
5285 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5286 needsTransform = TRUE;
5289 /* Extra transformation specified by caller */
5290 if (!is_identity_MAT2(lpmat))
5293 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5294 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5295 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5296 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5297 pFT_Matrix_Multiply(&extraMat, &transMat);
5298 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5299 needsTransform = TRUE;
5302 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5303 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5304 format == GGO_GRAY8_BITMAP))
5306 load_flags |= FT_LOAD_NO_BITMAP;
5309 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5312 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5316 if(!needsTransform) {
5317 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5318 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5319 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5321 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5322 bottom = (ft_face->glyph->metrics.horiBearingY -
5323 ft_face->glyph->metrics.height) & -64;
5324 lpgm->gmCellIncX = adv;
5325 lpgm->gmCellIncY = 0;
5332 for(xc = 0; xc < 2; xc++) {
5333 for(yc = 0; yc < 2; yc++) {
5334 vec.x = (ft_face->glyph->metrics.horiBearingX +
5335 xc * ft_face->glyph->metrics.width);
5336 vec.y = ft_face->glyph->metrics.horiBearingY -
5337 yc * ft_face->glyph->metrics.height;
5338 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5339 pFT_Vector_Transform(&vec, &transMat);
5340 if(xc == 0 && yc == 0) {
5341 left = right = vec.x;
5342 top = bottom = vec.y;
5344 if(vec.x < left) left = vec.x;
5345 else if(vec.x > right) right = vec.x;
5346 if(vec.y < bottom) bottom = vec.y;
5347 else if(vec.y > top) top = vec.y;
5352 right = (right + 63) & -64;
5353 bottom = bottom & -64;
5354 top = (top + 63) & -64;
5356 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5357 vec.x = ft_face->glyph->metrics.horiAdvance;
5359 pFT_Vector_Transform(&vec, &transMat);
5360 lpgm->gmCellIncX = (vec.x+63) >> 6;
5361 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5363 vec.x = ft_face->glyph->metrics.horiAdvance;
5365 pFT_Vector_Transform(&vec, &transMatUnrotated);
5366 adv = (vec.x+63) >> 6;
5370 bbx = (right - left) >> 6;
5371 lpgm->gmBlackBoxX = (right - left) >> 6;
5372 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5373 lpgm->gmptGlyphOrigin.x = left >> 6;
5374 lpgm->gmptGlyphOrigin.y = top >> 6;
5376 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5377 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5378 lpgm->gmCellIncX, lpgm->gmCellIncY);
5380 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5381 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5383 FONT_GM(font,original_index)->gm = *lpgm;
5384 FONT_GM(font,original_index)->adv = adv;
5385 FONT_GM(font,original_index)->lsb = lsb;
5386 FONT_GM(font,original_index)->bbx = bbx;
5387 FONT_GM(font,original_index)->init = TRUE;
5390 if(format == GGO_METRICS)
5392 return 1; /* FIXME */
5395 if(ft_face->glyph->format != ft_glyph_format_outline &&
5396 (format == GGO_NATIVE || format == GGO_BEZIER))
5398 TRACE("loaded a bitmap\n");
5404 width = lpgm->gmBlackBoxX;
5405 height = lpgm->gmBlackBoxY;
5406 pitch = ((width + 31) >> 5) << 2;
5407 needed = pitch * height;
5409 if(!buf || !buflen) break;
5411 switch(ft_face->glyph->format) {
5412 case ft_glyph_format_bitmap:
5414 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5415 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5416 INT h = ft_face->glyph->bitmap.rows;
5418 memcpy(dst, src, w);
5419 src += ft_face->glyph->bitmap.pitch;
5425 case ft_glyph_format_outline:
5426 ft_bitmap.width = width;
5427 ft_bitmap.rows = height;
5428 ft_bitmap.pitch = pitch;
5429 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5430 ft_bitmap.buffer = buf;
5433 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5435 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5437 /* Note: FreeType will only set 'black' bits for us. */
5438 memset(buf, 0, needed);
5439 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5443 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5448 case GGO_GRAY2_BITMAP:
5449 case GGO_GRAY4_BITMAP:
5450 case GGO_GRAY8_BITMAP:
5451 case WINE_GGO_GRAY16_BITMAP:
5453 unsigned int max_level, row, col;
5456 width = lpgm->gmBlackBoxX;
5457 height = lpgm->gmBlackBoxY;
5458 pitch = (width + 3) / 4 * 4;
5459 needed = pitch * height;
5461 if(!buf || !buflen) break;
5463 max_level = get_max_level( format );
5465 switch(ft_face->glyph->format) {
5466 case ft_glyph_format_bitmap:
5468 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5469 INT h = ft_face->glyph->bitmap.rows;
5471 memset( buf, 0, needed );
5473 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5474 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5475 src += ft_face->glyph->bitmap.pitch;
5480 case ft_glyph_format_outline:
5482 ft_bitmap.width = width;
5483 ft_bitmap.rows = height;
5484 ft_bitmap.pitch = pitch;
5485 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5486 ft_bitmap.buffer = buf;
5489 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5491 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5493 memset(ft_bitmap.buffer, 0, buflen);
5495 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5497 if (max_level != 255)
5499 for (row = 0, start = buf; row < height; row++)
5501 for (col = 0, ptr = start; col < width; col++, ptr++)
5502 *ptr = (((int)*ptr) * max_level + 128) / 256;
5510 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5516 case WINE_GGO_HRGB_BITMAP:
5517 case WINE_GGO_HBGR_BITMAP:
5518 case WINE_GGO_VRGB_BITMAP:
5519 case WINE_GGO_VBGR_BITMAP:
5520 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5522 switch (ft_face->glyph->format)
5524 case FT_GLYPH_FORMAT_BITMAP:
5529 width = lpgm->gmBlackBoxX;
5530 height = lpgm->gmBlackBoxY;
5532 needed = pitch * height;
5534 if (!buf || !buflen) break;
5536 memset(buf, 0, buflen);
5538 src = ft_face->glyph->bitmap.buffer;
5539 src_pitch = ft_face->glyph->bitmap.pitch;
5541 height = min( height, ft_face->glyph->bitmap.rows );
5544 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5546 if ( src[x / 8] & masks[x % 8] )
5547 ((unsigned int *)dst)[x] = ~0u;
5556 case FT_GLYPH_FORMAT_OUTLINE:
5560 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5561 INT x_shift, y_shift;
5563 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5564 FT_Render_Mode render_mode =
5565 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5566 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5568 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5570 if ( render_mode == FT_RENDER_MODE_LCD)
5572 lpgm->gmBlackBoxX += 2;
5573 lpgm->gmptGlyphOrigin.x -= 1;
5577 lpgm->gmBlackBoxY += 2;
5578 lpgm->gmptGlyphOrigin.y += 1;
5582 width = lpgm->gmBlackBoxX;
5583 height = lpgm->gmBlackBoxY;
5585 needed = pitch * height;
5587 if (!buf || !buflen) break;
5589 memset(buf, 0, buflen);
5591 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5593 if ( needsTransform )
5594 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5596 if ( pFT_Library_SetLcdFilter )
5597 pFT_Library_SetLcdFilter( library, lcdfilter );
5598 pFT_Render_Glyph (ft_face->glyph, render_mode);
5600 src = ft_face->glyph->bitmap.buffer;
5601 src_pitch = ft_face->glyph->bitmap.pitch;
5602 src_width = ft_face->glyph->bitmap.width;
5603 src_height = ft_face->glyph->bitmap.rows;
5605 if ( render_mode == FT_RENDER_MODE_LCD)
5613 rgb_interval = src_pitch;
5618 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5619 if ( x_shift < 0 ) x_shift = 0;
5620 if ( x_shift + (src_width / hmul) > width )
5621 x_shift = width - (src_width / hmul);
5623 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5624 if ( y_shift < 0 ) y_shift = 0;
5625 if ( y_shift + (src_height / vmul) > height )
5626 y_shift = height - (src_height / vmul);
5628 dst += x_shift + y_shift * ( pitch / 4 );
5629 while ( src_height )
5631 for ( x = 0; x < src_width / hmul; x++ )
5635 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5636 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5637 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5638 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5642 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5643 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5644 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5645 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5648 src += src_pitch * vmul;
5657 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5669 int contour, point = 0, first_pt;
5670 FT_Outline *outline = &ft_face->glyph->outline;
5671 TTPOLYGONHEADER *pph;
5673 DWORD pph_start, cpfx, type;
5675 if(buflen == 0) buf = NULL;
5677 if (needsTransform && buf) {
5678 pFT_Outline_Transform(outline, &transMat);
5681 for(contour = 0; contour < outline->n_contours; contour++) {
5683 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5686 pph->dwType = TT_POLYGON_TYPE;
5687 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5689 needed += sizeof(*pph);
5691 while(point <= outline->contours[contour]) {
5692 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5693 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5694 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5698 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5701 } while(point <= outline->contours[contour] &&
5702 (outline->tags[point] & FT_Curve_Tag_On) ==
5703 (outline->tags[point-1] & FT_Curve_Tag_On));
5704 /* At the end of a contour Windows adds the start point, but
5706 if(point > outline->contours[contour] &&
5707 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5709 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5711 } else if(point <= outline->contours[contour] &&
5712 outline->tags[point] & FT_Curve_Tag_On) {
5713 /* add closing pt for bezier */
5715 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5723 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5726 pph->cb = needed - pph_start;
5732 /* Convert the quadratic Beziers to cubic Beziers.
5733 The parametric eqn for a cubic Bezier is, from PLRM:
5734 r(t) = at^3 + bt^2 + ct + r0
5735 with the control points:
5740 A quadratic Bezier has the form:
5741 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5743 So equating powers of t leads to:
5744 r1 = 2/3 p1 + 1/3 p0
5745 r2 = 2/3 p1 + 1/3 p2
5746 and of course r0 = p0, r3 = p2
5749 int contour, point = 0, first_pt;
5750 FT_Outline *outline = &ft_face->glyph->outline;
5751 TTPOLYGONHEADER *pph;
5753 DWORD pph_start, cpfx, type;
5754 FT_Vector cubic_control[4];
5755 if(buflen == 0) buf = NULL;
5757 if (needsTransform && buf) {
5758 pFT_Outline_Transform(outline, &transMat);
5761 for(contour = 0; contour < outline->n_contours; contour++) {
5763 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5766 pph->dwType = TT_POLYGON_TYPE;
5767 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5769 needed += sizeof(*pph);
5771 while(point <= outline->contours[contour]) {
5772 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5773 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5774 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5777 if(type == TT_PRIM_LINE) {
5779 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5783 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5786 /* FIXME: Possible optimization in endpoint calculation
5787 if there are two consecutive curves */
5788 cubic_control[0] = outline->points[point-1];
5789 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5790 cubic_control[0].x += outline->points[point].x + 1;
5791 cubic_control[0].y += outline->points[point].y + 1;
5792 cubic_control[0].x >>= 1;
5793 cubic_control[0].y >>= 1;
5795 if(point+1 > outline->contours[contour])
5796 cubic_control[3] = outline->points[first_pt];
5798 cubic_control[3] = outline->points[point+1];
5799 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5800 cubic_control[3].x += outline->points[point].x + 1;
5801 cubic_control[3].y += outline->points[point].y + 1;
5802 cubic_control[3].x >>= 1;
5803 cubic_control[3].y >>= 1;
5806 /* r1 = 1/3 p0 + 2/3 p1
5807 r2 = 1/3 p2 + 2/3 p1 */
5808 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5809 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5810 cubic_control[2] = cubic_control[1];
5811 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5812 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5813 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5814 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5816 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5817 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5818 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5823 } while(point <= outline->contours[contour] &&
5824 (outline->tags[point] & FT_Curve_Tag_On) ==
5825 (outline->tags[point-1] & FT_Curve_Tag_On));
5826 /* At the end of a contour Windows adds the start point,
5827 but only for Beziers and we've already done that.
5829 if(point <= outline->contours[contour] &&
5830 outline->tags[point] & FT_Curve_Tag_On) {
5831 /* This is the closing pt of a bezier, but we've already
5832 added it, so just inc point and carry on */
5839 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5842 pph->cb = needed - pph_start;
5848 FIXME("Unsupported format %d\n", format);
5854 static BOOL get_bitmap_text_metrics(GdiFont *font)
5856 FT_Face ft_face = font->ft_face;
5857 FT_WinFNT_HeaderRec winfnt_header;
5858 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5859 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5860 font->potm->otmSize = size;
5862 #define TM font->potm->otmTextMetrics
5863 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5865 TM.tmHeight = winfnt_header.pixel_height;
5866 TM.tmAscent = winfnt_header.ascent;
5867 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5868 TM.tmInternalLeading = winfnt_header.internal_leading;
5869 TM.tmExternalLeading = winfnt_header.external_leading;
5870 TM.tmAveCharWidth = winfnt_header.avg_width;
5871 TM.tmMaxCharWidth = winfnt_header.max_width;
5872 TM.tmWeight = winfnt_header.weight;
5874 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5875 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5876 TM.tmFirstChar = winfnt_header.first_char;
5877 TM.tmLastChar = winfnt_header.last_char;
5878 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5879 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5880 TM.tmItalic = winfnt_header.italic;
5881 TM.tmUnderlined = font->underline;
5882 TM.tmStruckOut = font->strikeout;
5883 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5884 TM.tmCharSet = winfnt_header.charset;
5888 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5889 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5890 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5891 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5892 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5893 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5894 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5895 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5897 TM.tmDigitizedAspectX = 96; /* FIXME */
5898 TM.tmDigitizedAspectY = 96; /* FIXME */
5900 TM.tmLastChar = 255;
5901 TM.tmDefaultChar = 32;
5902 TM.tmBreakChar = 32;
5903 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5904 TM.tmUnderlined = font->underline;
5905 TM.tmStruckOut = font->strikeout;
5906 /* NB inverted meaning of TMPF_FIXED_PITCH */
5907 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5908 TM.tmCharSet = font->charset;
5916 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5918 double scale_x, scale_y;
5922 scale_x = (double)font->aveWidth;
5923 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5926 scale_x = font->scale_y;
5928 scale_x *= fabs(font->font_desc.matrix.eM11);
5929 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5931 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5932 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5934 SCALE_Y(ptm->tmHeight);
5935 SCALE_Y(ptm->tmAscent);
5936 SCALE_Y(ptm->tmDescent);
5937 SCALE_Y(ptm->tmInternalLeading);
5938 SCALE_Y(ptm->tmExternalLeading);
5939 SCALE_Y(ptm->tmOverhang);
5941 SCALE_X(ptm->tmAveCharWidth);
5942 SCALE_X(ptm->tmMaxCharWidth);
5948 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5950 double scale_x, scale_y;
5954 scale_x = (double)font->aveWidth;
5955 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5958 scale_x = font->scale_y;
5960 scale_x *= fabs(font->font_desc.matrix.eM11);
5961 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5963 scale_font_metrics(font, &potm->otmTextMetrics);
5965 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5966 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5968 SCALE_Y(potm->otmAscent);
5969 SCALE_Y(potm->otmDescent);
5970 SCALE_Y(potm->otmLineGap);
5971 SCALE_Y(potm->otmsCapEmHeight);
5972 SCALE_Y(potm->otmsXHeight);
5973 SCALE_Y(potm->otmrcFontBox.top);
5974 SCALE_Y(potm->otmrcFontBox.bottom);
5975 SCALE_X(potm->otmrcFontBox.left);
5976 SCALE_X(potm->otmrcFontBox.right);
5977 SCALE_Y(potm->otmMacAscent);
5978 SCALE_Y(potm->otmMacDescent);
5979 SCALE_Y(potm->otmMacLineGap);
5980 SCALE_X(potm->otmptSubscriptSize.x);
5981 SCALE_Y(potm->otmptSubscriptSize.y);
5982 SCALE_X(potm->otmptSubscriptOffset.x);
5983 SCALE_Y(potm->otmptSubscriptOffset.y);
5984 SCALE_X(potm->otmptSuperscriptSize.x);
5985 SCALE_Y(potm->otmptSuperscriptSize.y);
5986 SCALE_X(potm->otmptSuperscriptOffset.x);
5987 SCALE_Y(potm->otmptSuperscriptOffset.y);
5988 SCALE_Y(potm->otmsStrikeoutSize);
5989 SCALE_Y(potm->otmsStrikeoutPosition);
5990 SCALE_Y(potm->otmsUnderscoreSize);
5991 SCALE_Y(potm->otmsUnderscorePosition);
5997 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6001 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6003 /* Make sure that the font has sane width/height ratio */
6006 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6008 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6013 *ptm = font->potm->otmTextMetrics;
6014 scale_font_metrics(font, ptm);
6018 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6022 for(i = 0; i < ft_face->num_charmaps; i++)
6024 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6030 static BOOL get_outline_text_metrics(GdiFont *font)
6033 FT_Face ft_face = font->ft_face;
6034 UINT needed, lenfam, lensty;
6036 TT_HoriHeader *pHori;
6037 TT_Postscript *pPost;
6038 FT_Fixed x_scale, y_scale;
6039 WCHAR *family_nameW, *style_nameW;
6040 static const WCHAR spaceW[] = {' ', '\0'};
6042 INT ascent, descent;
6044 TRACE("font=%p\n", font);
6046 if(!FT_IS_SCALABLE(ft_face))
6049 needed = sizeof(*font->potm);
6051 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6052 family_nameW = strdupW(font->name);
6054 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6056 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6057 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6058 style_nameW, lensty/sizeof(WCHAR));
6060 /* These names should be read from the TT name table */
6062 /* length of otmpFamilyName */
6065 /* length of otmpFaceName */
6066 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6067 needed += lenfam; /* just the family name */
6069 needed += lenfam + lensty; /* family + " " + style */
6072 /* length of otmpStyleName */
6075 /* length of otmpFullName */
6076 needed += lenfam + lensty;
6079 x_scale = ft_face->size->metrics.x_scale;
6080 y_scale = ft_face->size->metrics.y_scale;
6082 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6084 FIXME("Can't find OS/2 table - not TT font?\n");
6088 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6090 FIXME("Can't find HHEA table - not TT font?\n");
6094 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6096 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",
6097 pOS2->usWinAscent, pOS2->usWinDescent,
6098 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6099 ft_face->ascender, ft_face->descender, ft_face->height,
6100 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6101 ft_face->bbox.yMax, ft_face->bbox.yMin);
6103 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6104 font->potm->otmSize = needed;
6106 #define TM font->potm->otmTextMetrics
6108 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6109 ascent = pHori->Ascender;
6110 descent = -pHori->Descender;
6112 ascent = pOS2->usWinAscent;
6113 descent = pOS2->usWinDescent;
6117 TM.tmAscent = font->yMax;
6118 TM.tmDescent = -font->yMin;
6119 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6121 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6122 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6123 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6124 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6127 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6130 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6132 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6133 ((ascent + descent) -
6134 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6136 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6137 if (TM.tmAveCharWidth == 0) {
6138 TM.tmAveCharWidth = 1;
6140 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6141 TM.tmWeight = FW_REGULAR;
6142 if (font->fake_bold)
6143 TM.tmWeight = FW_BOLD;
6146 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6148 if (pOS2->usWeightClass > FW_MEDIUM)
6149 TM.tmWeight = pOS2->usWeightClass;
6151 else if (pOS2->usWeightClass <= FW_MEDIUM)
6152 TM.tmWeight = pOS2->usWeightClass;
6155 TM.tmDigitizedAspectX = 300;
6156 TM.tmDigitizedAspectY = 300;
6157 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6158 * symbol range to 0 - f0ff
6161 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6166 case 1257: /* Baltic */
6167 TM.tmLastChar = 0xf8fd;
6170 TM.tmLastChar = 0xf0ff;
6172 TM.tmBreakChar = 0x20;
6173 TM.tmDefaultChar = 0x1f;
6177 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6178 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6180 if(pOS2->usFirstCharIndex <= 1)
6181 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6182 else if (pOS2->usFirstCharIndex > 0xff)
6183 TM.tmBreakChar = 0x20;
6185 TM.tmBreakChar = pOS2->usFirstCharIndex;
6186 TM.tmDefaultChar = TM.tmBreakChar - 1;
6188 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6189 TM.tmUnderlined = font->underline;
6190 TM.tmStruckOut = font->strikeout;
6192 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6193 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6194 (pOS2->version == 0xFFFFU ||
6195 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6196 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6198 TM.tmPitchAndFamily = 0;
6200 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6202 case PAN_FAMILY_SCRIPT:
6203 TM.tmPitchAndFamily |= FF_SCRIPT;
6206 case PAN_FAMILY_DECORATIVE:
6207 TM.tmPitchAndFamily |= FF_DECORATIVE;
6212 case PAN_FAMILY_TEXT_DISPLAY:
6213 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6214 /* which is clearly not what the panose spec says. */
6216 if(TM.tmPitchAndFamily == 0 || /* fixed */
6217 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6218 TM.tmPitchAndFamily = FF_MODERN;
6221 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6226 TM.tmPitchAndFamily |= FF_DONTCARE;
6229 case PAN_SERIF_COVE:
6230 case PAN_SERIF_OBTUSE_COVE:
6231 case PAN_SERIF_SQUARE_COVE:
6232 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6233 case PAN_SERIF_SQUARE:
6234 case PAN_SERIF_THIN:
6235 case PAN_SERIF_BONE:
6236 case PAN_SERIF_EXAGGERATED:
6237 case PAN_SERIF_TRIANGLE:
6238 TM.tmPitchAndFamily |= FF_ROMAN;
6241 case PAN_SERIF_NORMAL_SANS:
6242 case PAN_SERIF_OBTUSE_SANS:
6243 case PAN_SERIF_PERP_SANS:
6244 case PAN_SERIF_FLARED:
6245 case PAN_SERIF_ROUNDED:
6246 TM.tmPitchAndFamily |= FF_SWISS;
6253 if(FT_IS_SCALABLE(ft_face))
6254 TM.tmPitchAndFamily |= TMPF_VECTOR;
6256 if(FT_IS_SFNT(ft_face))
6258 if (font->ntmFlags & NTM_PS_OPENTYPE)
6259 TM.tmPitchAndFamily |= TMPF_DEVICE;
6261 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6264 TM.tmCharSet = font->charset;
6266 font->potm->otmFiller = 0;
6267 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6268 font->potm->otmfsSelection = pOS2->fsSelection;
6269 font->potm->otmfsType = pOS2->fsType;
6270 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6271 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6272 font->potm->otmItalicAngle = 0; /* POST table */
6273 font->potm->otmEMSquare = ft_face->units_per_EM;
6274 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6275 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6276 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6277 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6278 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6279 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6280 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6281 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6282 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6283 font->potm->otmMacAscent = TM.tmAscent;
6284 font->potm->otmMacDescent = -TM.tmDescent;
6285 font->potm->otmMacLineGap = font->potm->otmLineGap;
6286 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6287 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6288 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6289 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6290 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6291 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6292 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6293 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6294 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6295 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6296 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6298 font->potm->otmsUnderscoreSize = 0;
6299 font->potm->otmsUnderscorePosition = 0;
6301 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6302 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6306 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6307 cp = (char*)font->potm + sizeof(*font->potm);
6308 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6309 strcpyW((WCHAR*)cp, family_nameW);
6311 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6312 strcpyW((WCHAR*)cp, style_nameW);
6314 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6315 strcpyW((WCHAR*)cp, family_nameW);
6316 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6317 strcatW((WCHAR*)cp, spaceW);
6318 strcatW((WCHAR*)cp, style_nameW);
6319 cp += lenfam + lensty;
6322 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6323 strcpyW((WCHAR*)cp, family_nameW);
6324 strcatW((WCHAR*)cp, spaceW);
6325 strcatW((WCHAR*)cp, style_nameW);
6329 HeapFree(GetProcessHeap(), 0, style_nameW);
6330 HeapFree(GetProcessHeap(), 0, family_nameW);
6334 /*************************************************************
6335 * freetype_GetGlyphOutline
6337 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6338 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6340 struct freetype_physdev *physdev = get_freetype_dev( dev );
6345 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6346 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6350 EnterCriticalSection( &freetype_cs );
6351 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6352 LeaveCriticalSection( &freetype_cs );
6356 /*************************************************************
6357 * freetype_GetTextMetrics
6359 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6361 struct freetype_physdev *physdev = get_freetype_dev( dev );
6366 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6367 return dev->funcs->pGetTextMetrics( dev, metrics );
6371 EnterCriticalSection( &freetype_cs );
6372 ret = get_text_metrics( physdev->font, metrics );
6373 LeaveCriticalSection( &freetype_cs );
6377 /*************************************************************
6378 * freetype_GetOutlineTextMetrics
6380 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6382 struct freetype_physdev *physdev = get_freetype_dev( dev );
6387 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6388 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6391 TRACE("font=%p\n", physdev->font);
6393 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6396 EnterCriticalSection( &freetype_cs );
6398 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6400 if(cbSize >= physdev->font->potm->otmSize)
6402 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6403 scale_outline_font_metrics(physdev->font, potm);
6405 ret = physdev->font->potm->otmSize;
6407 LeaveCriticalSection( &freetype_cs );
6411 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6413 HFONTLIST *hfontlist;
6414 child->font = alloc_font();
6415 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6416 if(!child->font->ft_face)
6418 free_font(child->font);
6423 child->font->font_desc = font->font_desc;
6424 child->font->ntmFlags = child->face->ntmFlags;
6425 child->font->orientation = font->orientation;
6426 child->font->scale_y = font->scale_y;
6427 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6428 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6429 child->font->name = strdupW(child->face->family->FamilyName);
6430 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6431 child->font->base_font = font;
6432 list_add_head(&child_font_list, &child->font->entry);
6433 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6437 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6440 CHILD_FONT *child_font;
6443 font = font->base_font;
6445 *linked_font = font;
6447 if((*glyph = get_glyph_index(font, c)))
6449 *glyph = get_GSUB_vert_glyph(font, *glyph);
6453 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6455 if(!child_font->font)
6456 if(!load_child_font(font, child_font))
6459 if(!child_font->font->ft_face)
6461 g = get_glyph_index(child_font->font, c);
6462 g = get_GSUB_vert_glyph(child_font->font, g);
6466 *linked_font = child_font->font;
6473 /*************************************************************
6474 * freetype_GetCharWidth
6476 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6478 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6481 FT_UInt glyph_index;
6482 GdiFont *linked_font;
6483 struct freetype_physdev *physdev = get_freetype_dev( dev );
6487 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6488 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6491 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6494 EnterCriticalSection( &freetype_cs );
6495 for(c = firstChar; c <= lastChar; c++) {
6496 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6497 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6498 &gm, 0, NULL, &identity);
6499 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6501 LeaveCriticalSection( &freetype_cs );
6505 /*************************************************************
6506 * freetype_GetCharABCWidths
6508 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6510 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6513 FT_UInt glyph_index;
6514 GdiFont *linked_font;
6515 struct freetype_physdev *physdev = get_freetype_dev( dev );
6519 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6520 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6523 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6526 EnterCriticalSection( &freetype_cs );
6528 for(c = firstChar; c <= lastChar; c++) {
6529 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6530 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6531 &gm, 0, NULL, &identity);
6532 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6533 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6534 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6535 FONT_GM(linked_font,glyph_index)->bbx;
6537 LeaveCriticalSection( &freetype_cs );
6541 /*************************************************************
6542 * freetype_GetCharABCWidthsI
6544 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6546 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6549 FT_UInt glyph_index;
6550 GdiFont *linked_font;
6551 struct freetype_physdev *physdev = get_freetype_dev( dev );
6555 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6556 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6559 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6563 EnterCriticalSection( &freetype_cs );
6565 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6567 for(c = firstChar; c < firstChar+count; c++) {
6568 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6569 &gm, 0, NULL, &identity);
6570 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6571 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6572 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6573 - FONT_GM(linked_font,c)->bbx;
6576 for(c = 0; c < count; c++) {
6577 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6578 &gm, 0, NULL, &identity);
6579 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6580 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6581 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6582 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6585 LeaveCriticalSection( &freetype_cs );
6589 /*************************************************************
6590 * freetype_GetTextExtentExPoint
6592 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6593 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6595 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6600 FT_UInt glyph_index;
6601 GdiFont *linked_font;
6602 struct freetype_physdev *physdev = get_freetype_dev( dev );
6606 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6607 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6610 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6613 EnterCriticalSection( &freetype_cs );
6616 get_text_metrics( physdev->font, &tm );
6617 size->cy = tm.tmHeight;
6619 for(idx = 0; idx < count; idx++) {
6620 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6621 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6622 &gm, 0, NULL, &identity);
6623 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6625 if (! pnfit || ext <= max_ext) {
6635 LeaveCriticalSection( &freetype_cs );
6636 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6640 /*************************************************************
6641 * freetype_GetTextExtentExPointI
6643 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6644 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6646 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6651 struct freetype_physdev *physdev = get_freetype_dev( dev );
6655 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6656 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6659 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6662 EnterCriticalSection( &freetype_cs );
6665 get_text_metrics(physdev->font, &tm);
6666 size->cy = tm.tmHeight;
6668 for(idx = 0; idx < count; idx++) {
6669 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6670 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6672 if (! pnfit || ext <= max_ext) {
6682 LeaveCriticalSection( &freetype_cs );
6683 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6687 /*************************************************************
6688 * freetype_GetFontData
6690 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6692 struct freetype_physdev *physdev = get_freetype_dev( dev );
6696 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6697 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6700 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6701 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6702 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6704 return get_font_data( physdev->font, table, offset, buf, cbData );
6707 /*************************************************************
6708 * freetype_GetTextFace
6710 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6713 struct freetype_physdev *physdev = get_freetype_dev( dev );
6717 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6718 return dev->funcs->pGetTextFace( dev, count, str );
6721 n = strlenW(physdev->font->name) + 1;
6724 lstrcpynW(str, physdev->font->name, count);
6730 /*************************************************************
6731 * freetype_GetTextCharsetInfo
6733 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6735 struct freetype_physdev *physdev = get_freetype_dev( dev );
6739 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6740 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6742 if (fs) *fs = physdev->font->fs;
6743 return physdev->font->charset;
6746 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6748 GdiFont *font = dc->gdiFont, *linked_font;
6749 struct list *first_hfont;
6753 EnterCriticalSection( &freetype_cs );
6754 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6755 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6756 if(font == linked_font)
6757 *new_hfont = dc->hFont;
6760 first_hfont = list_head(&linked_font->hfontlist);
6761 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6763 LeaveCriticalSection( &freetype_cs );
6767 /* Retrieve a list of supported Unicode ranges for a given font.
6768 * Can be called with NULL gs to calculate the buffer size. Returns
6769 * the number of ranges found.
6771 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6773 DWORD num_ranges = 0;
6775 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6778 FT_ULong char_code, char_code_prev;
6781 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6783 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6784 face->num_glyphs, glyph_code, char_code);
6786 if (!glyph_code) return 0;
6790 gs->ranges[0].wcLow = (USHORT)char_code;
6791 gs->ranges[0].cGlyphs = 0;
6792 gs->cGlyphsSupported = 0;
6798 if (char_code < char_code_prev)
6800 ERR("expected increasing char code from FT_Get_Next_Char\n");
6803 if (char_code - char_code_prev > 1)
6808 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6809 gs->ranges[num_ranges - 1].cGlyphs = 1;
6810 gs->cGlyphsSupported++;
6815 gs->ranges[num_ranges - 1].cGlyphs++;
6816 gs->cGlyphsSupported++;
6818 char_code_prev = char_code;
6819 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6823 FIXME("encoding %u not supported\n", face->charmap->encoding);
6828 /*************************************************************
6829 * freetype_GetFontUnicodeRanges
6831 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6833 struct freetype_physdev *physdev = get_freetype_dev( dev );
6834 DWORD size, num_ranges;
6838 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6839 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6842 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6843 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6846 glyphset->cbThis = size;
6847 glyphset->cRanges = num_ranges;
6848 glyphset->flAccel = 0;
6853 /*************************************************************
6854 * freetype_FontIsLinked
6856 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6858 struct freetype_physdev *physdev = get_freetype_dev( dev );
6863 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6864 return dev->funcs->pFontIsLinked( dev );
6868 EnterCriticalSection( &freetype_cs );
6869 ret = !list_empty(&physdev->font->child_fonts);
6870 LeaveCriticalSection( &freetype_cs );
6874 static BOOL is_hinting_enabled(void)
6876 /* Use the >= 2.2.0 function if available */
6877 if(pFT_Get_TrueType_Engine_Type)
6879 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6880 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6882 #ifdef FT_DRIVER_HAS_HINTER
6887 /* otherwise if we've been compiled with < 2.2.0 headers
6888 use the internal macro */
6889 mod = pFT_Get_Module(library, "truetype");
6890 if(mod && FT_DRIVER_HAS_HINTER(mod))
6898 static BOOL is_subpixel_rendering_enabled( void )
6900 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6901 return pFT_Library_SetLcdFilter &&
6902 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6908 /*************************************************************************
6909 * GetRasterizerCaps (GDI32.@)
6911 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6913 static int hinting = -1;
6914 static int subpixel = -1;
6918 hinting = is_hinting_enabled();
6919 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6922 if ( subpixel == -1 )
6924 subpixel = is_subpixel_rendering_enabled();
6925 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6928 lprs->nSize = sizeof(RASTERIZER_STATUS);
6929 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6931 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6932 lprs->nLanguageID = 0;
6936 /*************************************************************
6937 * freetype_GdiRealizationInfo
6939 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6941 struct freetype_physdev *physdev = get_freetype_dev( dev );
6942 realization_info_t *info = ptr;
6946 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6947 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6950 FIXME("(%p, %p): stub!\n", physdev->font, info);
6953 if(FT_IS_SCALABLE(physdev->font->ft_face))
6956 info->cache_num = physdev->font->cache_num;
6957 info->unknown2 = -1;
6961 /*************************************************************************
6962 * Kerning support for TrueType fonts
6964 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6966 struct TT_kern_table
6972 struct TT_kern_subtable
6981 USHORT horizontal : 1;
6983 USHORT cross_stream: 1;
6984 USHORT override : 1;
6985 USHORT reserved1 : 4;
6991 struct TT_format0_kern_subtable
6995 USHORT entrySelector;
7006 static DWORD parse_format0_kern_subtable(GdiFont *font,
7007 const struct TT_format0_kern_subtable *tt_f0_ks,
7008 const USHORT *glyph_to_char,
7009 KERNINGPAIR *kern_pair, DWORD cPairs)
7012 const struct TT_kern_pair *tt_kern_pair;
7014 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7016 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7018 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7019 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7020 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7022 if (!kern_pair || !cPairs)
7025 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7027 nPairs = min(nPairs, cPairs);
7029 for (i = 0; i < nPairs; i++)
7031 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7032 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7033 /* this algorithm appears to better match what Windows does */
7034 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7035 if (kern_pair->iKernAmount < 0)
7037 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7038 kern_pair->iKernAmount -= font->ppem;
7040 else if (kern_pair->iKernAmount > 0)
7042 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7043 kern_pair->iKernAmount += font->ppem;
7045 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7047 TRACE("left %u right %u value %d\n",
7048 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7052 TRACE("copied %u entries\n", nPairs);
7056 /*************************************************************
7057 * freetype_GetKerningPairs
7059 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7063 const struct TT_kern_table *tt_kern_table;
7064 const struct TT_kern_subtable *tt_kern_subtable;
7066 USHORT *glyph_to_char;
7068 struct freetype_physdev *physdev = get_freetype_dev( dev );
7070 if (!(font = physdev->font))
7072 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7073 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7077 EnterCriticalSection( &freetype_cs );
7078 if (font->total_kern_pairs != (DWORD)-1)
7080 if (cPairs && kern_pair)
7082 cPairs = min(cPairs, font->total_kern_pairs);
7083 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7085 else cPairs = font->total_kern_pairs;
7087 LeaveCriticalSection( &freetype_cs );
7091 font->total_kern_pairs = 0;
7093 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7095 if (length == GDI_ERROR)
7097 TRACE("no kerning data in the font\n");
7098 LeaveCriticalSection( &freetype_cs );
7102 buf = HeapAlloc(GetProcessHeap(), 0, length);
7105 WARN("Out of memory\n");
7106 LeaveCriticalSection( &freetype_cs );
7110 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7112 /* build a glyph index to char code map */
7113 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7116 WARN("Out of memory allocating a glyph index to char code map\n");
7117 HeapFree(GetProcessHeap(), 0, buf);
7118 LeaveCriticalSection( &freetype_cs );
7122 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7128 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7130 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7131 font->ft_face->num_glyphs, glyph_code, char_code);
7135 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7137 /* FIXME: This doesn't match what Windows does: it does some fancy
7138 * things with duplicate glyph index to char code mappings, while
7139 * we just avoid overriding existing entries.
7141 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7142 glyph_to_char[glyph_code] = (USHORT)char_code;
7144 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7151 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7152 for (n = 0; n <= 65535; n++)
7153 glyph_to_char[n] = (USHORT)n;
7156 tt_kern_table = buf;
7157 nTables = GET_BE_WORD(tt_kern_table->nTables);
7158 TRACE("version %u, nTables %u\n",
7159 GET_BE_WORD(tt_kern_table->version), nTables);
7161 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7163 for (i = 0; i < nTables; i++)
7165 struct TT_kern_subtable tt_kern_subtable_copy;
7167 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7168 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7169 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7171 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7172 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7173 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7175 /* According to the TrueType specification this is the only format
7176 * that will be properly interpreted by Windows and OS/2
7178 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7180 DWORD new_chunk, old_total = font->total_kern_pairs;
7182 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7183 glyph_to_char, NULL, 0);
7184 font->total_kern_pairs += new_chunk;
7186 if (!font->kern_pairs)
7187 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7188 font->total_kern_pairs * sizeof(*font->kern_pairs));
7190 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7191 font->total_kern_pairs * sizeof(*font->kern_pairs));
7193 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7194 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7197 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7199 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7202 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7203 HeapFree(GetProcessHeap(), 0, buf);
7205 if (cPairs && kern_pair)
7207 cPairs = min(cPairs, font->total_kern_pairs);
7208 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7210 else cPairs = font->total_kern_pairs;
7212 LeaveCriticalSection( &freetype_cs );
7216 static const struct gdi_dc_funcs freetype_funcs =
7218 NULL, /* pAbortDoc */
7219 NULL, /* pAbortPath */
7220 NULL, /* pAlphaBlend */
7221 NULL, /* pAngleArc */
7224 NULL, /* pBeginPath */
7225 NULL, /* pBlendImage */
7226 NULL, /* pChoosePixelFormat */
7228 NULL, /* pCloseFigure */
7229 NULL, /* pCopyBitmap */
7230 NULL, /* pCreateBitmap */
7231 NULL, /* pCreateCompatibleDC */
7232 freetype_CreateDC, /* pCreateDC */
7233 NULL, /* pDeleteBitmap */
7234 freetype_DeleteDC, /* pDeleteDC */
7235 NULL, /* pDeleteObject */
7236 NULL, /* pDescribePixelFormat */
7237 NULL, /* pDeviceCapabilities */
7238 NULL, /* pEllipse */
7240 NULL, /* pEndPage */
7241 NULL, /* pEndPath */
7242 freetype_EnumFonts, /* pEnumFonts */
7243 NULL, /* pEnumICMProfiles */
7244 NULL, /* pExcludeClipRect */
7245 NULL, /* pExtDeviceMode */
7246 NULL, /* pExtEscape */
7247 NULL, /* pExtFloodFill */
7248 NULL, /* pExtSelectClipRgn */
7249 NULL, /* pExtTextOut */
7250 NULL, /* pFillPath */
7251 NULL, /* pFillRgn */
7252 NULL, /* pFlattenPath */
7253 freetype_FontIsLinked, /* pFontIsLinked */
7254 NULL, /* pFrameRgn */
7255 NULL, /* pGdiComment */
7256 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7257 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7258 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7259 freetype_GetCharWidth, /* pGetCharWidth */
7260 NULL, /* pGetDeviceCaps */
7261 NULL, /* pGetDeviceGammaRamp */
7262 freetype_GetFontData, /* pGetFontData */
7263 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7264 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7265 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7266 NULL, /* pGetICMProfile */
7267 NULL, /* pGetImage */
7268 freetype_GetKerningPairs, /* pGetKerningPairs */
7269 NULL, /* pGetNearestColor */
7270 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7271 NULL, /* pGetPixel */
7272 NULL, /* pGetPixelFormat */
7273 NULL, /* pGetSystemPaletteEntries */
7274 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7275 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7276 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7277 freetype_GetTextFace, /* pGetTextFace */
7278 freetype_GetTextMetrics, /* pGetTextMetrics */
7279 NULL, /* pGradientFill */
7280 NULL, /* pIntersectClipRect */
7281 NULL, /* pInvertRgn */
7283 NULL, /* pModifyWorldTransform */
7285 NULL, /* pOffsetClipRgn */
7286 NULL, /* pOffsetViewportOrg */
7287 NULL, /* pOffsetWindowOrg */
7288 NULL, /* pPaintRgn */
7291 NULL, /* pPolyBezier */
7292 NULL, /* pPolyBezierTo */
7293 NULL, /* pPolyDraw */
7294 NULL, /* pPolyPolygon */
7295 NULL, /* pPolyPolyline */
7296 NULL, /* pPolygon */
7297 NULL, /* pPolyline */
7298 NULL, /* pPolylineTo */
7299 NULL, /* pPutImage */
7300 NULL, /* pRealizeDefaultPalette */
7301 NULL, /* pRealizePalette */
7302 NULL, /* pRectangle */
7303 NULL, /* pResetDC */
7304 NULL, /* pRestoreDC */
7305 NULL, /* pRoundRect */
7307 NULL, /* pScaleViewportExt */
7308 NULL, /* pScaleWindowExt */
7309 NULL, /* pSelectBitmap */
7310 NULL, /* pSelectBrush */
7311 NULL, /* pSelectClipPath */
7312 freetype_SelectFont, /* pSelectFont */
7313 NULL, /* pSelectPalette */
7314 NULL, /* pSelectPen */
7315 NULL, /* pSetArcDirection */
7316 NULL, /* pSetBkColor */
7317 NULL, /* pSetBkMode */
7318 NULL, /* pSetDCBrushColor */
7319 NULL, /* pSetDCPenColor */
7320 NULL, /* pSetDIBColorTable */
7321 NULL, /* pSetDIBitsToDevice */
7322 NULL, /* pSetDeviceClipping */
7323 NULL, /* pSetDeviceGammaRamp */
7324 NULL, /* pSetLayout */
7325 NULL, /* pSetMapMode */
7326 NULL, /* pSetMapperFlags */
7327 NULL, /* pSetPixel */
7328 NULL, /* pSetPixelFormat */
7329 NULL, /* pSetPolyFillMode */
7330 NULL, /* pSetROP2 */
7331 NULL, /* pSetRelAbs */
7332 NULL, /* pSetStretchBltMode */
7333 NULL, /* pSetTextAlign */
7334 NULL, /* pSetTextCharacterExtra */
7335 NULL, /* pSetTextColor */
7336 NULL, /* pSetTextJustification */
7337 NULL, /* pSetViewportExt */
7338 NULL, /* pSetViewportOrg */
7339 NULL, /* pSetWindowExt */
7340 NULL, /* pSetWindowOrg */
7341 NULL, /* pSetWorldTransform */
7342 NULL, /* pStartDoc */
7343 NULL, /* pStartPage */
7344 NULL, /* pStretchBlt */
7345 NULL, /* pStretchDIBits */
7346 NULL, /* pStrokeAndFillPath */
7347 NULL, /* pStrokePath */
7348 NULL, /* pSwapBuffers */
7349 NULL, /* pUnrealizePalette */
7350 NULL, /* pWidenPath */
7351 /* OpenGL not supported */
7354 #else /* HAVE_FREETYPE */
7356 /*************************************************************************/
7358 BOOL WineEngInit(void)
7362 BOOL WineEngDestroyFontInstance(HFONT hfont)
7367 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7369 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7373 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7375 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7379 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7381 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7385 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7390 /*************************************************************************
7391 * GetRasterizerCaps (GDI32.@)
7393 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7395 lprs->nSize = sizeof(RASTERIZER_STATUS);
7397 lprs->nLanguageID = 0;
7401 #endif /* HAVE_FREETYPE */