2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
98 #ifdef HAVE_FT2BUILD_H
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
144 static FT_Library library = 0;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix);
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetString);
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
241 FT_Short internal_leading;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
255 NEWTEXTMETRICEXW ntm;
259 typedef struct tagFace {
265 DWORD font_data_size;
269 FT_Fixed font_version;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
279 typedef struct tagFamily {
281 const WCHAR *FamilyName;
282 const WCHAR *EnglishName;
284 struct list *replacement;
289 INT adv; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST {
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping *mapping;
353 const WCHAR *font_name;
358 struct enum_charset_element {
361 WCHAR name[LF_FACESIZE];
364 struct enum_charset_list {
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 struct freetype_physdev
384 struct gdi_physdev dev;
388 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
390 return (struct freetype_physdev *)dev;
393 static const struct gdi_dc_funcs freetype_funcs;
395 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR * const SystemFontValues[] = {
422 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
428 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
438 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
439 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR *default_serif_list[] =
450 bitstream_vera_serif,
454 static const WCHAR *default_fixed_list[] =
458 bitstream_vera_sans_mono,
462 static const WCHAR *default_sans_list[] =
475 typedef struct tagFontSubst {
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
487 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
488 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
489 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
491 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
511 static struct list mappings_list = LIST_INIT( mappings_list );
513 static CRITICAL_SECTION freetype_cs;
514 static CRITICAL_SECTION_DEBUG critsect_debug =
517 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
518 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback = FALSE;
527 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
528 static BOOL get_outline_text_metrics(GdiFont *font);
529 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
531 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
547 * FIXEDFON.FON FixedSys
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
589 GSUB_ScriptRecord ScriptRecord[1];
595 } GSUB_LangSysRecord;
600 GSUB_LangSysRecord LangSysRecord[1];
604 WORD LookupOrder; /* Reserved */
605 WORD ReqFeatureIndex;
607 WORD FeatureIndex[1];
613 } GSUB_FeatureRecord;
617 GSUB_FeatureRecord FeatureRecord[1];
621 WORD FeatureParams; /* Reserved */
623 WORD LookupListIndex[1];
642 } GSUB_CoverageFormat1;
647 WORD StartCoverageIndex;
653 GSUB_RangeRecord RangeRecord[1];
654 } GSUB_CoverageFormat2;
657 WORD SubstFormat; /* = 1 */
660 } GSUB_SingleSubstFormat1;
663 WORD SubstFormat; /* = 2 */
667 }GSUB_SingleSubstFormat2;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
674 static char cached_path[MAX_PATH];
675 static const char *wine = "/Wine", *fonts = "/Fonts";
677 if(*cached_path) return cached_path;
679 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
682 WARN("can't create cached data folder\n");
685 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
688 WARN("can't create cached data path\n");
692 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
694 ERR("Could not create full path\n");
698 strcat(cached_path, wine);
700 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
702 WARN("Couldn't mkdir %s\n", cached_path);
706 strcat(cached_path, fonts);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
716 /******************************************************************
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path)
734 const char *filename;
738 unsigned int size, max_size;
741 TRACE("path %s\n", path);
743 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
746 WARN("failed to get ref\n");
750 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref = FSOpenResFile(&ref, fsRdPerm);
757 TRACE("unable to open resource fork\n");
764 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
767 CloseResFile(res_ref);
771 out_dir = find_cache_dir();
773 filename = strrchr(path, '/');
774 if(!filename) filename = path;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
785 unsigned short *num_faces_ptr, num_faces, face;
788 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
790 fond = Get1IndResource(fond_res, idx);
792 TRACE("got fond resource %d\n", idx);
795 fam_rec = *(FamRec**)fond;
796 num_faces_ptr = (unsigned short *)(fam_rec + 1);
797 num_faces = GET_BE_WORD(*num_faces_ptr);
799 assoc = (AsscEntry*)(num_faces_ptr + 1);
800 TRACE("num faces %04x\n", num_faces);
801 for(face = 0; face < num_faces; face++, assoc++)
804 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
805 unsigned short size, font_id;
808 size = GET_BE_WORD(assoc->fontSize);
809 font_id = GET_BE_WORD(assoc->fontID);
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
816 TRACE("trying to load sfnt id %04x\n", font_id);
817 sfnt = GetResource(sfnt_res, font_id);
820 TRACE("can't get sfnt resource %04x\n", font_id);
824 output = HeapAlloc(GetProcessHeap(), 0, output_len);
829 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
831 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
832 if(fd != -1 || errno == EEXIST)
836 unsigned char *sfnt_data;
839 sfnt_data = *(unsigned char**)sfnt;
840 write(fd, sfnt_data, GetHandleSize(sfnt));
844 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
847 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
849 ret.array[ret.size++] = output;
853 WARN("unable to create %s\n", output);
854 HeapFree(GetProcessHeap(), 0, output);
857 ReleaseResource(sfnt);
860 ReleaseResource(fond);
863 CloseResFile(res_ref);
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed FT_FixedFromFloat(double f)
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
889 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
893 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
898 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
899 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
901 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
902 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
904 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
906 if(face_name && strcmpiW(face_name, family->FamilyName))
908 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
912 file = strrchr(face->file, '/');
917 if(!strcasecmp(file, file_nameA))
919 HeapFree(GetProcessHeap(), 0, file_nameA);
924 HeapFree(GetProcessHeap(), 0, file_nameA);
928 static Family *find_family_from_name(const WCHAR *name)
932 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
934 if(!strcmpiW(family->FamilyName, name))
941 static Family *find_family_from_any_name(const WCHAR *name)
945 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
947 if(!strcmpiW(family->FamilyName, name))
949 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
956 static void DumpSubstList(void)
960 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
962 if(psub->from.charset != -1 || psub->to.charset != -1)
963 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
964 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
966 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
967 debugstr_w(psub->to.name));
972 static LPWSTR strdupW(LPCWSTR p)
975 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
976 ret = HeapAlloc(GetProcessHeap(), 0, len);
981 static LPSTR strdupA(LPCSTR p)
984 DWORD len = (strlen(p) + 1);
985 ret = HeapAlloc(GetProcessHeap(), 0, len);
990 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
995 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
997 if(!strcmpiW(element->from.name, from_name) &&
998 (element->from.charset == from_charset ||
999 element->from.charset == -1))
1006 #define ADD_FONT_SUBST_FORCE 1
1008 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1010 FontSubst *from_exist, *to_exist;
1012 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1014 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1016 list_remove(&from_exist->entry);
1017 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1018 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1019 HeapFree(GetProcessHeap(), 0, from_exist);
1025 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1029 HeapFree(GetProcessHeap(), 0, subst->to.name);
1030 subst->to.name = strdupW(to_exist->to.name);
1033 list_add_tail(subst_list, &subst->entry);
1038 HeapFree(GetProcessHeap(), 0, subst->from.name);
1039 HeapFree(GetProcessHeap(), 0, subst->to.name);
1040 HeapFree(GetProcessHeap(), 0, subst);
1044 static WCHAR *towstr(UINT cp, const char *str)
1049 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1050 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1051 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1055 static void split_subst_info(NameCs *nc, LPSTR str)
1057 CHAR *p = strrchr(str, ',');
1061 nc->charset = strtol(p+1, NULL, 10);
1064 nc->name = towstr(CP_ACP, str);
1067 static void LoadSubstList(void)
1071 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1075 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1076 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1077 &hkey) == ERROR_SUCCESS) {
1079 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1080 &valuelen, &datalen, NULL, NULL);
1082 valuelen++; /* returned value doesn't include room for '\0' */
1083 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1084 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1088 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1089 &dlen) == ERROR_SUCCESS) {
1090 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1092 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1093 split_subst_info(&psub->from, value);
1094 split_subst_info(&psub->to, data);
1096 /* Win 2000 doesn't allow mapping between different charsets
1097 or mapping of DEFAULT_CHARSET */
1098 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1099 psub->to.charset == DEFAULT_CHARSET) {
1100 HeapFree(GetProcessHeap(), 0, psub->to.name);
1101 HeapFree(GetProcessHeap(), 0, psub->from.name);
1102 HeapFree(GetProcessHeap(), 0, psub);
1104 add_font_subst(&font_subst_list, psub, 0);
1106 /* reset dlen and vlen */
1110 HeapFree(GetProcessHeap(), 0, data);
1111 HeapFree(GetProcessHeap(), 0, value);
1117 /*****************************************************************
1118 * get_name_table_entry
1120 * Supply the platform, encoding, language and name ids in req
1121 * and if the name exists the function will fill in the string
1122 * and string_len members. The string is owned by FreeType so
1123 * don't free it. Returns TRUE if the name is found else FALSE.
1125 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1128 FT_UInt num_names, name_index;
1130 if(FT_IS_SFNT(ft_face))
1132 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1134 for(name_index = 0; name_index < num_names; name_index++)
1136 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1138 if((name.platform_id == req->platform_id) &&
1139 (name.encoding_id == req->encoding_id) &&
1140 (name.language_id == req->language_id) &&
1141 (name.name_id == req->name_id))
1143 req->string = name.string;
1144 req->string_len = name.string_len;
1151 req->string_len = 0;
1155 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1160 name.platform_id = TT_PLATFORM_MICROSOFT;
1161 name.encoding_id = TT_MS_ID_UNICODE_CS;
1162 name.language_id = language_id;
1163 name.name_id = name_id;
1165 if(get_name_table_entry(ft_face, &name))
1169 /* String is not nul terminated and string_len is a byte length. */
1170 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1171 for(i = 0; i < name.string_len / 2; i++)
1173 WORD *tmp = (WORD *)&name.string[i * 2];
1174 ret[i] = GET_BE_WORD(*tmp);
1177 TRACE("Got localised name %s\n", debugstr_w(ret));
1183 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1186 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1187 if(r != ERROR_SUCCESS) return r;
1188 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1189 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1192 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1194 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1197 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1200 DWORD num_strikes, max_strike_key_len;
1202 /* If we have a File Name key then this is a real font, not just the parent
1203 key of a bunch of non-scalable strikes */
1204 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1208 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1209 face->cached_enum_data = NULL;
1211 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1212 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1214 face->StyleName = strdupW(face_name);
1215 face->family = family;
1216 face->vertical = (family->FamilyName[0] == '@');
1218 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1220 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1221 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1222 face->FullName = fullName;
1225 face->FullName = NULL;
1227 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1228 reg_load_dword(hkey_face, face_italic_value, &italic);
1229 reg_load_dword(hkey_face, face_bold_value, &bold);
1230 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1231 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1233 needed = sizeof(face->fs);
1234 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
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 family->replacement = &family->faces;
1328 list_add_tail(&font_list, &family->entry);
1332 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1333 subst->from.name = strdupW(english_family);
1334 subst->from.charset = -1;
1335 subst->to.name = strdupW(family_name);
1336 subst->to.charset = -1;
1337 add_font_subst(&font_subst_list, subst, 0);
1340 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1341 NULL, NULL, NULL, NULL);
1343 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1344 size = max_face_key_len + 1;
1345 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1346 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1350 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1351 load_face(hkey_face, face_name, family);
1352 RegCloseKey(hkey_face);
1353 size = max_face_key_len + 1;
1355 HeapFree(GetProcessHeap(), 0, face_name);
1356 RegCloseKey(hkey_family);
1357 size = max_family_key_len + 1;
1360 HeapFree(GetProcessHeap(), 0, family_name);
1363 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1366 HKEY hkey_wine_fonts;
1368 /* We don't want to create the fonts key as volatile, so open this first */
1369 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1370 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1371 if(ret != ERROR_SUCCESS)
1373 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1377 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1378 KEY_ALL_ACCESS, NULL, hkey, disposition);
1379 RegCloseKey(hkey_wine_fonts);
1383 static void add_face_to_cache(Face *face)
1385 HKEY hkey_font_cache, hkey_family, hkey_face;
1386 WCHAR *face_key_name;
1388 create_font_cache_key(&hkey_font_cache, NULL);
1390 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1391 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1392 if(face->family->EnglishName)
1393 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1394 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1397 face_key_name = face->StyleName;
1400 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1401 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1402 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1404 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1407 HeapFree(GetProcessHeap(), 0, face_key_name);
1409 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1411 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1412 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1414 reg_save_dword(hkey_face, face_index_value, face->face_index);
1415 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1416 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1417 reg_save_dword(hkey_face, face_version_value, face->font_version);
1418 reg_save_dword(hkey_face, face_external_value, face->external);
1420 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1424 reg_save_dword(hkey_face, face_height_value, face->size.height);
1425 reg_save_dword(hkey_face, face_width_value, face->size.width);
1426 reg_save_dword(hkey_face, face_size_value, face->size.size);
1427 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1428 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1429 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1431 RegCloseKey(hkey_face);
1432 RegCloseKey(hkey_family);
1433 RegCloseKey(hkey_font_cache);
1436 static inline int TestStyles(DWORD flags, DWORD styles)
1438 return (flags & styles) == styles;
1441 static int StyleOrdering(Face *face)
1443 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1445 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1447 if (TestStyles(face->ntmFlags, NTM_BOLD))
1449 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1452 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1453 debugstr_w(face->family->FamilyName),
1454 debugstr_w(face->StyleName),
1460 /* Add a style of face to a font family using an ordering of the list such
1461 that regular fonts come before bold and italic, and single styles come
1462 before compound styles. */
1463 static void AddFaceToFamily(Face *face, Family *family)
1467 LIST_FOR_EACH( entry, &family->faces )
1469 Face *ent = LIST_ENTRY(entry, Face, entry);
1470 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1472 list_add_before( entry, &face->entry );
1475 static WCHAR *prepend_at(WCHAR *family)
1482 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1484 strcpyW(str + 1, family);
1485 HeapFree(GetProcessHeap(), 0, family);
1489 #define ADDFONT_EXTERNAL_FONT 0x01
1490 #define ADDFONT_FORCE_BITMAP 0x02
1491 #define ADDFONT_ADD_TO_CACHE 0x04
1493 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size, FT_Long face_index, DWORD flags, BOOL vertical)
1502 WCHAR *english_family, *localised_family;
1504 struct list *face_elem_ptr;
1505 FT_WinFNT_HeaderRec winfnt_header;
1506 int internal_leading;
1508 My_FT_Bitmap_Size *size = NULL;
1511 if(!FT_IS_SCALABLE(ft_face))
1512 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1514 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1515 if (!english_family)
1516 english_family = towstr(CP_ACP, ft_face->family_name);
1518 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1519 if (localised_family && !strcmpiW(localised_family, english_family))
1521 HeapFree(GetProcessHeap(), 0, localised_family);
1522 localised_family = NULL;
1527 english_family = prepend_at(english_family);
1528 localised_family = prepend_at(localised_family);
1531 family = find_family_from_name(localised_family ? localised_family : english_family);
1533 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1534 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1535 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1536 list_init(&family->faces);
1537 family->replacement = &family->faces;
1538 list_add_tail(&font_list, &family->entry);
1540 if(localised_family) {
1541 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1542 subst->from.name = strdupW(english_family);
1543 subst->from.charset = -1;
1544 subst->to.name = strdupW(localised_family);
1545 subst->to.charset = -1;
1546 add_font_subst(&font_subst_list, subst, 0);
1549 HeapFree(GetProcessHeap(), 0, localised_family);
1550 HeapFree(GetProcessHeap(), 0, english_family);
1552 StyleW = towstr(CP_ACP, ft_face->style_name);
1554 internal_leading = 0;
1555 memset(&fs, 0, sizeof(fs));
1557 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1559 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1560 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1561 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1562 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1563 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1564 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1565 if(pOS2->version == 0) {
1568 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1569 fs.fsCsb[0] |= FS_LATIN1;
1571 fs.fsCsb[0] |= FS_SYMBOL;
1574 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1576 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1577 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1578 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1580 internal_leading = winfnt_header.internal_leading;
1583 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1584 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1585 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1586 if(!strcmpiW(face->StyleName, StyleW) &&
1587 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1588 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1589 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1590 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1592 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1593 TRACE("Original font is newer so skipping this one\n");
1594 HeapFree(GetProcessHeap(), 0, StyleW);
1597 TRACE("Replacing original with this one\n");
1598 list_remove(&face->entry);
1599 HeapFree(GetProcessHeap(), 0, face->file);
1600 HeapFree(GetProcessHeap(), 0, face->StyleName);
1601 HeapFree(GetProcessHeap(), 0, face->FullName);
1602 HeapFree(GetProcessHeap(), 0, face);
1607 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1608 face->cached_enum_data = NULL;
1609 face->StyleName = StyleW;
1610 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1613 face->file = strdupA(file);
1614 face->font_data_ptr = NULL;
1615 face->font_data_size = 0;
1620 face->font_data_ptr = font_data_ptr;
1621 face->font_data_size = font_data_size;
1623 face->face_index = face_index;
1625 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1626 face->ntmFlags |= NTM_ITALIC;
1627 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1628 face->ntmFlags |= NTM_BOLD;
1629 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1630 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1631 face->family = family;
1632 face->vertical = vertical;
1633 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1636 if(FT_IS_SCALABLE(ft_face)) {
1637 memset(&face->size, 0, sizeof(face->size));
1638 face->scalable = TRUE;
1640 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1641 size->height, size->width, size->size >> 6,
1642 size->x_ppem >> 6, size->y_ppem >> 6);
1643 face->size.height = size->height;
1644 face->size.width = size->width;
1645 face->size.size = size->size;
1646 face->size.x_ppem = size->x_ppem;
1647 face->size.y_ppem = size->y_ppem;
1648 face->size.internal_leading = internal_leading;
1649 face->scalable = FALSE;
1652 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1654 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1656 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1657 face->ntmFlags |= NTM_PS_OPENTYPE;
1660 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1661 face->fs.fsCsb[0], face->fs.fsCsb[1],
1662 face->fs.fsUsb[0], face->fs.fsUsb[1],
1663 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1665 if(face->fs.fsCsb[0] == 0)
1669 /* let's see if we can find any interesting cmaps */
1670 for(i = 0; i < ft_face->num_charmaps; i++) {
1671 switch(ft_face->charmaps[i]->encoding) {
1672 case FT_ENCODING_UNICODE:
1673 case FT_ENCODING_APPLE_ROMAN:
1674 face->fs.fsCsb[0] |= FS_LATIN1;
1676 case FT_ENCODING_MS_SYMBOL:
1677 face->fs.fsCsb[0] |= FS_SYMBOL;
1685 if(flags & ADDFONT_ADD_TO_CACHE)
1686 add_face_to_cache(face);
1688 AddFaceToFamily(face, family);
1690 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1692 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1693 debugstr_w(StyleW));
1696 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1700 TT_Header *pHeader = NULL;
1702 FT_Long face_index = 0, num_faces;
1705 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1706 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1708 #ifdef HAVE_CARBON_CARBON_H
1711 char **mac_list = expand_mac_font(file);
1714 BOOL had_one = FALSE;
1716 for(cursor = mac_list; *cursor; cursor++)
1719 AddFontToList(*cursor, NULL, 0, flags);
1720 HeapFree(GetProcessHeap(), 0, *cursor);
1722 HeapFree(GetProcessHeap(), 0, mac_list);
1727 #endif /* HAVE_CARBON_CARBON_H */
1732 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1733 err = pFT_New_Face(library, file, face_index, &ft_face);
1736 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1737 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1741 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1745 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*/
1746 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1747 pFT_Done_Face(ft_face);
1751 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1752 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1753 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1754 pFT_Done_Face(ft_face);
1758 if(FT_IS_SFNT(ft_face))
1760 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1761 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1762 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1764 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1765 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1766 pFT_Done_Face(ft_face);
1770 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1771 we don't want to load these. */
1772 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1776 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1778 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1779 pFT_Done_Face(ft_face);
1785 if(!ft_face->family_name || !ft_face->style_name) {
1786 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1787 pFT_Done_Face(ft_face);
1791 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1793 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1794 pFT_Done_Face(ft_face);
1798 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1801 if (FT_HAS_VERTICAL(ft_face))
1803 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1807 num_faces = ft_face->num_faces;
1808 pFT_Done_Face(ft_face);
1809 } while(num_faces > ++face_index);
1813 static void DumpFontList(void)
1817 struct list *family_elem_ptr, *face_elem_ptr;
1819 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1820 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1821 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1822 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1823 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1824 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1826 TRACE(" %d", face->size.height);
1833 /***********************************************************
1834 * The replacement list is a way to map an entire font
1835 * family onto another family. For example adding
1837 * [HKCU\Software\Wine\Fonts\Replacements]
1838 * "Wingdings"="Winedings"
1840 * would enumerate the Winedings font both as Winedings and
1841 * Wingdings. However if a real Wingdings font is present the
1842 * replacement does not take place.
1845 static void LoadReplaceList(void)
1848 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1853 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1854 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1856 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1857 &valuelen, &datalen, NULL, NULL);
1859 valuelen++; /* returned value doesn't include room for '\0' */
1860 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1861 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1865 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1866 &dlen) == ERROR_SUCCESS) {
1867 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1868 /* "NewName"="Oldname" */
1869 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1871 if(!find_family_from_any_name(value))
1873 Family * const family = find_family_from_any_name(data);
1876 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1877 if (new_family != NULL)
1879 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1880 new_family->FamilyName = strdupW(value);
1881 new_family->EnglishName = NULL;
1882 list_init(&new_family->faces);
1883 new_family->replacement = &family->faces;
1884 list_add_tail(&font_list, &new_family->entry);
1889 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1894 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1896 /* reset dlen and vlen */
1900 HeapFree(GetProcessHeap(), 0, data);
1901 HeapFree(GetProcessHeap(), 0, value);
1906 static const WCHAR *font_links_list[] =
1908 Lucida_Sans_Unicode,
1909 Microsoft_Sans_Serif,
1913 static const struct font_links_defaults_list
1915 /* Keyed off substitution for "MS Shell Dlg" */
1916 const WCHAR *shelldlg;
1917 /* Maximum of four substitutes, plus terminating NULL pointer */
1918 const WCHAR *substitutes[5];
1919 } font_links_defaults_list[] =
1921 /* Non East-Asian */
1922 { Tahoma, /* FIXME unverified ordering */
1923 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
1925 /* Below lists are courtesy of
1926 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1930 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
1932 /* Chinese Simplified */
1934 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
1938 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
1940 /* Chinese Traditional */
1942 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
1947 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
1949 SYSTEM_LINKS *font_link;
1951 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1953 if(!strcmpiW(font_link->font_name, name))
1960 static const struct list *get_face_list_from_family(const Family *family)
1962 if (!list_empty(&family->faces))
1963 return &family->faces;
1965 return family->replacement;
1968 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
1980 SYSTEM_LINKS *font_link;
1982 psub = get_font_subst(&font_subst_list, name, -1);
1983 /* Don't store fonts that are only substitutes for other fonts */
1986 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
1990 font_link = find_font_link(name);
1991 if (font_link == NULL)
1993 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1994 font_link->font_name = strdupW(name);
1995 list_init(&font_link->links);
1996 list_add_tail(&system_links, &font_link->entry);
1999 memset(&font_link->fs, 0, sizeof font_link->fs);
2000 for (i = 0; values[i] != NULL; i++)
2002 const struct list *face_list;
2003 CHILD_FONT *child_font;
2006 if (!strcmpiW(name,value))
2008 psub = get_font_subst(&font_subst_list, value, -1);
2010 value = psub->to.name;
2011 family = find_family_from_name(value);
2015 /* Use first extant filename for this Family */
2016 face_list = get_face_list_from_family(family);
2017 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2021 file = strrchr(face->file, '/');
2030 fileW = towstr(CP_UNIXCP, file);
2032 face = find_face_from_filename(fileW, value);
2035 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2039 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2040 child_font->face = face;
2041 child_font->font = NULL;
2042 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2043 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2044 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2045 list_add_tail(&font_link->links, &child_font->entry);
2047 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2048 HeapFree(GetProcessHeap(), 0, fileW);
2054 /*************************************************************
2057 static BOOL init_system_links(void)
2061 DWORD type, max_val, max_data, val_len, data_len, index;
2062 WCHAR *value, *data;
2063 WCHAR *entry, *next;
2064 SYSTEM_LINKS *font_link, *system_font_link;
2065 CHILD_FONT *child_font;
2066 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2067 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2068 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2073 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2075 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2076 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2077 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2078 val_len = max_val + 1;
2079 data_len = max_data;
2081 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2083 psub = get_font_subst(&font_subst_list, value, -1);
2084 /* Don't store fonts that are only substitutes for other fonts */
2087 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2090 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2091 font_link->font_name = strdupW(value);
2092 memset(&font_link->fs, 0, sizeof font_link->fs);
2093 list_init(&font_link->links);
2094 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2097 CHILD_FONT *child_font;
2099 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2101 next = entry + strlenW(entry) + 1;
2103 face_name = strchrW(entry, ',');
2107 while(isspaceW(*face_name))
2110 psub = get_font_subst(&font_subst_list, face_name, -1);
2112 face_name = psub->to.name;
2114 face = find_face_from_filename(entry, face_name);
2117 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2121 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2122 child_font->face = face;
2123 child_font->font = NULL;
2124 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2125 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2126 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2127 list_add_tail(&font_link->links, &child_font->entry);
2129 list_add_tail(&system_links, &font_link->entry);
2131 val_len = max_val + 1;
2132 data_len = max_data;
2135 HeapFree(GetProcessHeap(), 0, value);
2136 HeapFree(GetProcessHeap(), 0, data);
2141 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2143 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2147 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2149 const FontSubst *psub2;
2150 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2152 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2154 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2155 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2157 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2158 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2160 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2162 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2168 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2171 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2172 system_font_link->font_name = strdupW(System);
2173 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2174 list_init(&system_font_link->links);
2176 face = find_face_from_filename(tahoma_ttf, Tahoma);
2179 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2180 child_font->face = face;
2181 child_font->font = NULL;
2182 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2183 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2184 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2185 list_add_tail(&system_font_link->links, &child_font->entry);
2187 font_link = find_font_link(Tahoma);
2188 if (font_link != NULL)
2190 CHILD_FONT *font_link_entry;
2191 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2193 CHILD_FONT *new_child;
2194 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2195 new_child->face = font_link_entry->face;
2196 new_child->font = NULL;
2197 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2198 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2199 list_add_tail(&system_font_link->links, &new_child->entry);
2202 list_add_tail(&system_links, &system_font_link->entry);
2206 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2209 struct dirent *dent;
2210 char path[MAX_PATH];
2212 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2214 dir = opendir(dirname);
2216 WARN("Can't open directory %s\n", debugstr_a(dirname));
2219 while((dent = readdir(dir)) != NULL) {
2220 struct stat statbuf;
2222 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2225 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2227 sprintf(path, "%s/%s", dirname, dent->d_name);
2229 if(stat(path, &statbuf) == -1)
2231 WARN("Can't stat %s\n", debugstr_a(path));
2234 if(S_ISDIR(statbuf.st_mode))
2235 ReadFontDir(path, external_fonts);
2238 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2239 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2240 AddFontToList(path, NULL, 0, addfont_flags);
2247 static void load_fontconfig_fonts(void)
2249 #ifdef SONAME_LIBFONTCONFIG
2250 void *fc_handle = NULL;
2259 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2261 TRACE("Wine cannot find the fontconfig library (%s).\n",
2262 SONAME_LIBFONTCONFIG);
2265 #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;}
2266 LOAD_FUNCPTR(FcConfigGetCurrent);
2267 LOAD_FUNCPTR(FcFontList);
2268 LOAD_FUNCPTR(FcFontSetDestroy);
2269 LOAD_FUNCPTR(FcInit);
2270 LOAD_FUNCPTR(FcObjectSetAdd);
2271 LOAD_FUNCPTR(FcObjectSetCreate);
2272 LOAD_FUNCPTR(FcObjectSetDestroy);
2273 LOAD_FUNCPTR(FcPatternCreate);
2274 LOAD_FUNCPTR(FcPatternDestroy);
2275 LOAD_FUNCPTR(FcPatternGetBool);
2276 LOAD_FUNCPTR(FcPatternGetString);
2279 if(!pFcInit()) return;
2281 config = pFcConfigGetCurrent();
2282 pat = pFcPatternCreate();
2283 os = pFcObjectSetCreate();
2284 pFcObjectSetAdd(os, FC_FILE);
2285 pFcObjectSetAdd(os, FC_SCALABLE);
2286 fontset = pFcFontList(config, pat, os);
2287 if(!fontset) return;
2288 for(i = 0; i < fontset->nfont; i++) {
2291 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2293 TRACE("fontconfig: %s\n", file);
2295 /* We're just interested in OT/TT fonts for now, so this hack just
2296 picks up the scalable fonts without extensions .pf[ab] to save time
2297 loading every other font */
2299 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2301 TRACE("not scalable\n");
2305 len = strlen( file );
2306 if(len < 4) continue;
2307 ext = &file[ len - 3 ];
2308 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2309 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2311 pFcFontSetDestroy(fontset);
2312 pFcObjectSetDestroy(os);
2313 pFcPatternDestroy(pat);
2319 static BOOL load_font_from_data_dir(LPCWSTR file)
2322 const char *data_dir = wine_get_data_dir();
2324 if (!data_dir) data_dir = wine_get_build_dir();
2331 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2333 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2335 strcpy(unix_name, data_dir);
2336 strcat(unix_name, "/fonts/");
2338 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2340 EnterCriticalSection( &freetype_cs );
2341 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2342 LeaveCriticalSection( &freetype_cs );
2343 HeapFree(GetProcessHeap(), 0, unix_name);
2348 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2350 static const WCHAR slashW[] = {'\\','\0'};
2352 WCHAR windowsdir[MAX_PATH];
2355 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2356 strcatW(windowsdir, fontsW);
2357 strcatW(windowsdir, slashW);
2358 strcatW(windowsdir, file);
2359 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2360 EnterCriticalSection( &freetype_cs );
2361 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2362 LeaveCriticalSection( &freetype_cs );
2363 HeapFree(GetProcessHeap(), 0, unixname);
2368 static void load_system_fonts(void)
2371 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2372 const WCHAR * const *value;
2374 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2377 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2378 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2379 strcatW(windowsdir, fontsW);
2380 for(value = SystemFontValues; *value; value++) {
2381 dlen = sizeof(data);
2382 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2386 sprintfW(pathW, fmtW, windowsdir, data);
2387 if((unixname = wine_get_unix_file_name(pathW))) {
2388 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2389 HeapFree(GetProcessHeap(), 0, unixname);
2392 load_font_from_data_dir(data);
2399 /*************************************************************
2401 * This adds registry entries for any externally loaded fonts
2402 * (fonts from fontconfig or FontDirs). It also deletes entries
2403 * of no longer existing fonts.
2406 static void update_reg_entries(void)
2408 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2413 struct list *family_elem_ptr, *face_elem_ptr;
2415 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2416 static const WCHAR spaceW[] = {' ', '\0'};
2419 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2420 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2421 ERR("Can't create Windows font reg key\n");
2425 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2426 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2427 ERR("Can't create Windows font reg key\n");
2431 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2432 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2433 ERR("Can't create external font reg key\n");
2437 /* enumerate the fonts and add external ones to the two keys */
2439 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2440 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2441 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2442 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2443 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2444 if(!face->external) continue;
2446 if (!(face->ntmFlags & NTM_REGULAR))
2447 len = len_fam + strlenW(face->StyleName) + 1;
2448 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2449 strcpyW(valueW, family->FamilyName);
2450 if(len != len_fam) {
2451 strcatW(valueW, spaceW);
2452 strcatW(valueW, face->StyleName);
2454 strcatW(valueW, TrueType);
2456 file = wine_get_dos_file_name(face->file);
2458 len = strlenW(file) + 1;
2461 if((path = strrchr(face->file, '/')) == NULL)
2465 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2467 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2468 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2470 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2471 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2472 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2474 HeapFree(GetProcessHeap(), 0, file);
2475 HeapFree(GetProcessHeap(), 0, valueW);
2479 if(external_key) RegCloseKey(external_key);
2480 if(win9x_key) RegCloseKey(win9x_key);
2481 if(winnt_key) RegCloseKey(winnt_key);
2485 static void delete_external_font_keys(void)
2487 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2488 DWORD dlen, vlen, datalen, valuelen, i, type;
2492 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2493 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2494 ERR("Can't create Windows font reg key\n");
2498 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2499 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2500 ERR("Can't create Windows font reg key\n");
2504 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2505 ERR("Can't create external font reg key\n");
2509 /* Delete all external fonts added last time */
2511 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2512 &valuelen, &datalen, NULL, NULL);
2513 valuelen++; /* returned value doesn't include room for '\0' */
2514 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2515 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2517 dlen = datalen * sizeof(WCHAR);
2520 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2521 &dlen) == ERROR_SUCCESS) {
2523 RegDeleteValueW(winnt_key, valueW);
2524 RegDeleteValueW(win9x_key, valueW);
2525 /* reset dlen and vlen */
2529 HeapFree(GetProcessHeap(), 0, data);
2530 HeapFree(GetProcessHeap(), 0, valueW);
2532 /* Delete the old external fonts key */
2533 RegCloseKey(external_key);
2534 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2537 if(win9x_key) RegCloseKey(win9x_key);
2538 if(winnt_key) RegCloseKey(winnt_key);
2541 /*************************************************************
2542 * WineEngAddFontResourceEx
2545 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2551 if (ft_handle) /* do it only if we have freetype up and running */
2556 FIXME("Ignoring flags %x\n", flags);
2558 if((unixname = wine_get_unix_file_name(file)))
2560 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2562 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2563 EnterCriticalSection( &freetype_cs );
2564 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2565 LeaveCriticalSection( &freetype_cs );
2566 HeapFree(GetProcessHeap(), 0, unixname);
2568 if (!ret && !strchrW(file, '\\')) {
2569 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2570 ret = load_font_from_winfonts_dir(file);
2572 /* Try in datadir/fonts (or builddir/fonts),
2573 * needed for Magic the Gathering Online
2575 ret = load_font_from_data_dir(file);
2582 /*************************************************************
2583 * WineEngAddFontMemResourceEx
2586 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2590 if (ft_handle) /* do it only if we have freetype up and running */
2592 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2594 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2595 memcpy(pFontCopy, pbFont, cbFont);
2597 EnterCriticalSection( &freetype_cs );
2598 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2599 LeaveCriticalSection( &freetype_cs );
2603 TRACE("AddFontToList failed\n");
2604 HeapFree(GetProcessHeap(), 0, pFontCopy);
2607 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2608 * For now return something unique but quite random
2610 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2611 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2618 /*************************************************************
2619 * WineEngRemoveFontResourceEx
2622 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2625 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2629 static const struct nls_update_font_list
2631 UINT ansi_cp, oem_cp;
2632 const char *oem, *fixed, *system;
2633 const char *courier, *serif, *small, *sserif;
2634 /* these are for font substitutes */
2635 const char *shelldlg, *tmsrmn;
2636 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2640 const char *from, *to;
2641 } arial_0, courier_new_0, times_new_roman_0;
2642 } nls_update_font_list[] =
2644 /* Latin 1 (United States) */
2645 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2646 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2647 "Tahoma","Times New Roman",
2648 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2651 /* Latin 1 (Multilingual) */
2652 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2653 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2654 "Tahoma","Times New Roman", /* FIXME unverified */
2655 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2658 /* Eastern Europe */
2659 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2660 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2661 "Tahoma","Times New Roman", /* FIXME unverified */
2662 "Fixedsys,238", "System,238",
2663 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2664 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2665 { "Arial CE,0", "Arial,238" },
2666 { "Courier New CE,0", "Courier New,238" },
2667 { "Times New Roman CE,0", "Times New Roman,238" }
2670 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2671 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2672 "Tahoma","Times New Roman", /* FIXME unverified */
2673 "Fixedsys,204", "System,204",
2674 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2675 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2676 { "Arial Cyr,0", "Arial,204" },
2677 { "Courier New Cyr,0", "Courier New,204" },
2678 { "Times New Roman Cyr,0", "Times New Roman,204" }
2681 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2682 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2683 "Tahoma","Times New Roman", /* FIXME unverified */
2684 "Fixedsys,161", "System,161",
2685 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2686 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2687 { "Arial Greek,0", "Arial,161" },
2688 { "Courier New Greek,0", "Courier New,161" },
2689 { "Times New Roman Greek,0", "Times New Roman,161" }
2692 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2693 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2694 "Tahoma","Times New Roman", /* FIXME unverified */
2695 "Fixedsys,162", "System,162",
2696 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2697 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2698 { "Arial Tur,0", "Arial,162" },
2699 { "Courier New Tur,0", "Courier New,162" },
2700 { "Times New Roman Tur,0", "Times New Roman,162" }
2703 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2704 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2705 "Tahoma","Times New Roman", /* FIXME unverified */
2706 "Fixedsys,177", "System,177",
2707 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2708 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2712 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2713 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2714 "Tahoma","Times New Roman", /* FIXME unverified */
2715 "Fixedsys,178", "System,178",
2716 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2717 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2721 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2722 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2723 "Tahoma","Times New Roman", /* FIXME unverified */
2724 "Fixedsys,186", "System,186",
2725 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2726 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2727 { "Arial Baltic,0", "Arial,186" },
2728 { "Courier New Baltic,0", "Courier New,186" },
2729 { "Times New Roman Baltic,0", "Times New Roman,186" }
2732 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2733 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2734 "Tahoma","Times New Roman", /* FIXME unverified */
2735 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2739 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2740 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2741 "Tahoma","Times New Roman", /* FIXME unverified */
2742 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2746 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2747 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2748 "MS UI Gothic","MS Serif",
2749 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2752 /* Chinese Simplified */
2753 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2754 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2755 "SimSun", "NSimSun",
2756 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2760 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2761 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2763 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2766 /* Chinese Traditional */
2767 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2768 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2769 "PMingLiU", "MingLiU",
2770 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2775 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2777 return ( ansi_cp == 932 /* CP932 for Japanese */
2778 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2779 || ansi_cp == 949 /* CP949 for Korean */
2780 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2783 static inline HKEY create_fonts_NT_registry_key(void)
2787 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2788 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2792 static inline HKEY create_fonts_9x_registry_key(void)
2796 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2797 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2801 static inline HKEY create_config_fonts_registry_key(void)
2805 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2806 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2810 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2812 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2813 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2814 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2815 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2818 static void set_value_key(HKEY hkey, const char *name, const char *value)
2821 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2823 RegDeleteValueA(hkey, name);
2826 static void update_font_info(void)
2828 char buf[40], cpbuf[40];
2831 UINT i, ansi_cp = 0, oem_cp = 0;
2834 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2837 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2838 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2839 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2840 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2841 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2843 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2844 if (is_dbcs_ansi_cp(ansi_cp))
2845 use_default_fallback = TRUE;
2848 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2850 if (!strcmp( buf, cpbuf )) /* already set correctly */
2855 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2857 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2859 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2862 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2866 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2867 nls_update_font_list[i].oem_cp == oem_cp)
2869 hkey = create_config_fonts_registry_key();
2870 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2871 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2872 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2875 hkey = create_fonts_NT_registry_key();
2876 add_font_list(hkey, &nls_update_font_list[i]);
2879 hkey = create_fonts_9x_registry_key();
2880 add_font_list(hkey, &nls_update_font_list[i]);
2883 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2885 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2886 strlen(nls_update_font_list[i].shelldlg)+1);
2887 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2888 strlen(nls_update_font_list[i].tmsrmn)+1);
2890 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2891 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2892 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2893 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2894 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2895 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2896 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2897 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2899 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2900 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2901 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2909 /* Delete the FontSubstitutes from other locales */
2910 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2912 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2913 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2914 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2920 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2923 static BOOL init_freetype(void)
2925 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2928 "Wine cannot find the FreeType font library. To enable Wine to\n"
2929 "use TrueType fonts please install a version of FreeType greater than\n"
2930 "or equal to 2.0.5.\n"
2931 "http://www.freetype.org\n");
2935 #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;}
2937 LOAD_FUNCPTR(FT_Done_Face)
2938 LOAD_FUNCPTR(FT_Get_Char_Index)
2939 LOAD_FUNCPTR(FT_Get_First_Char)
2940 LOAD_FUNCPTR(FT_Get_Module)
2941 LOAD_FUNCPTR(FT_Get_Next_Char)
2942 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2943 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2944 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2945 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2946 LOAD_FUNCPTR(FT_Init_FreeType)
2947 LOAD_FUNCPTR(FT_Library_Version)
2948 LOAD_FUNCPTR(FT_Load_Glyph)
2949 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2950 LOAD_FUNCPTR(FT_Matrix_Multiply)
2951 #ifndef FT_MULFIX_INLINED
2952 LOAD_FUNCPTR(FT_MulFix)
2954 LOAD_FUNCPTR(FT_New_Face)
2955 LOAD_FUNCPTR(FT_New_Memory_Face)
2956 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2957 LOAD_FUNCPTR(FT_Outline_Transform)
2958 LOAD_FUNCPTR(FT_Outline_Translate)
2959 LOAD_FUNCPTR(FT_Render_Glyph)
2960 LOAD_FUNCPTR(FT_Select_Charmap)
2961 LOAD_FUNCPTR(FT_Set_Charmap)
2962 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2963 LOAD_FUNCPTR(FT_Vector_Transform)
2964 LOAD_FUNCPTR(FT_Vector_Unit)
2966 /* Don't warn if these ones are missing */
2967 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2968 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2969 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2972 if(pFT_Init_FreeType(&library) != 0) {
2973 ERR("Can't init FreeType library\n");
2974 wine_dlclose(ft_handle, NULL, 0);
2978 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2980 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2981 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2982 ((FT_Version.minor << 8) & 0x00ff00) |
2983 ((FT_Version.patch ) & 0x0000ff);
2985 font_driver = &freetype_funcs;
2990 "Wine cannot find certain functions that it needs inside the FreeType\n"
2991 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2992 "FreeType to at least version 2.1.4.\n"
2993 "http://www.freetype.org\n");
2994 wine_dlclose(ft_handle, NULL, 0);
2999 static void init_font_list(void)
3001 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3002 static const WCHAR pathW[] = {'P','a','t','h',0};
3004 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3005 WCHAR windowsdir[MAX_PATH];
3008 const char *data_dir;
3010 delete_external_font_keys();
3012 /* load the system bitmap fonts */
3013 load_system_fonts();
3015 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3016 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3017 strcatW(windowsdir, fontsW);
3018 if((unixname = wine_get_unix_file_name(windowsdir)))
3020 ReadFontDir(unixname, FALSE);
3021 HeapFree(GetProcessHeap(), 0, unixname);
3024 /* load the system truetype fonts */
3025 data_dir = wine_get_data_dir();
3026 if (!data_dir) data_dir = wine_get_build_dir();
3027 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3029 strcpy(unixname, data_dir);
3030 strcat(unixname, "/fonts/");
3031 ReadFontDir(unixname, TRUE);
3032 HeapFree(GetProcessHeap(), 0, unixname);
3035 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3036 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3037 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3039 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3040 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3041 &hkey) == ERROR_SUCCESS)
3043 LPWSTR data, valueW;
3044 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3045 &valuelen, &datalen, NULL, NULL);
3047 valuelen++; /* returned value doesn't include room for '\0' */
3048 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3049 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3052 dlen = datalen * sizeof(WCHAR);
3054 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3055 &dlen) == ERROR_SUCCESS)
3057 if(data[0] && (data[1] == ':'))
3059 if((unixname = wine_get_unix_file_name(data)))
3061 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3062 HeapFree(GetProcessHeap(), 0, unixname);
3065 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3067 WCHAR pathW[MAX_PATH];
3068 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3071 sprintfW(pathW, fmtW, windowsdir, data);
3072 if((unixname = wine_get_unix_file_name(pathW)))
3074 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3075 HeapFree(GetProcessHeap(), 0, unixname);
3078 load_font_from_data_dir(data);
3080 /* reset dlen and vlen */
3085 HeapFree(GetProcessHeap(), 0, data);
3086 HeapFree(GetProcessHeap(), 0, valueW);
3090 load_fontconfig_fonts();
3092 /* then look in any directories that we've specified in the config file */
3093 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3094 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3100 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3102 len += sizeof(WCHAR);
3103 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3104 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3106 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3107 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3108 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3109 TRACE( "got font path %s\n", debugstr_a(valueA) );
3113 LPSTR next = strchr( ptr, ':' );
3114 if (next) *next++ = 0;
3115 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3116 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3118 strcpy( unixname, home );
3119 strcat( unixname, ptr + 1 );
3120 ReadFontDir( unixname, TRUE );
3121 HeapFree( GetProcessHeap(), 0, unixname );
3124 ReadFontDir( ptr, TRUE );
3127 HeapFree( GetProcessHeap(), 0, valueA );
3129 HeapFree( GetProcessHeap(), 0, valueW );
3135 /* Mac default font locations. */
3136 ReadFontDir( "/Library/Fonts", TRUE );
3137 ReadFontDir( "/Network/Library/Fonts", TRUE );
3138 ReadFontDir( "/System/Library/Fonts", TRUE );
3139 if ((home = getenv( "HOME" )))
3141 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3142 strcpy( unixname, home );
3143 strcat( unixname, "/Library/Fonts" );
3144 ReadFontDir( unixname, TRUE);
3145 HeapFree( GetProcessHeap(), 0, unixname );
3150 static BOOL move_to_front(const WCHAR *name)
3152 Family *family, *cursor2;
3153 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3155 if(!strcmpiW(family->FamilyName, name))
3157 list_remove(&family->entry);
3158 list_add_head(&font_list, &family->entry);
3165 static BOOL set_default(const WCHAR **name_list)
3169 if (move_to_front(*name_list)) return TRUE;
3176 static void reorder_font_list(void)
3178 set_default( default_serif_list );
3179 set_default( default_fixed_list );
3180 set_default( default_sans_list );
3183 /*************************************************************
3186 * Initialize FreeType library and create a list of available faces
3188 BOOL WineEngInit(void)
3190 HKEY hkey_font_cache;
3194 /* update locale dependent font info in registry */
3197 if(!init_freetype()) return FALSE;
3199 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3201 ERR("Failed to create font mutex\n");
3204 WaitForSingleObject(font_mutex, INFINITE);
3206 create_font_cache_key(&hkey_font_cache, &disposition);
3208 if(disposition == REG_CREATED_NEW_KEY)
3211 load_font_list_from_cache(hkey_font_cache);
3213 RegCloseKey(hkey_font_cache);
3215 reorder_font_list();
3222 if(disposition == REG_CREATED_NEW_KEY)
3223 update_reg_entries();
3225 init_system_links();
3227 ReleaseMutex(font_mutex);
3232 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3235 TT_HoriHeader *pHori;
3239 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3240 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3242 if(height == 0) height = 16;
3244 /* Calc. height of EM square:
3246 * For +ve lfHeight we have
3247 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3248 * Re-arranging gives:
3249 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3251 * For -ve lfHeight we have
3253 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3254 * with il = winAscent + winDescent - units_per_em]
3259 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3260 ppem = MulDiv(ft_face->units_per_EM, height,
3261 pHori->Ascender - pHori->Descender);
3263 ppem = MulDiv(ft_face->units_per_EM, height,
3264 pOS2->usWinAscent + pOS2->usWinDescent);
3272 static struct font_mapping *map_font_file( const char *name )
3274 struct font_mapping *mapping;
3278 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3279 if (fstat( fd, &st ) == -1) goto error;
3281 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3283 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3285 mapping->refcount++;
3290 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3293 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3296 if (mapping->data == MAP_FAILED)
3298 HeapFree( GetProcessHeap(), 0, mapping );
3301 mapping->refcount = 1;
3302 mapping->dev = st.st_dev;
3303 mapping->ino = st.st_ino;
3304 mapping->size = st.st_size;
3305 list_add_tail( &mappings_list, &mapping->entry );
3313 static void unmap_font_file( struct font_mapping *mapping )
3315 if (!--mapping->refcount)
3317 list_remove( &mapping->entry );
3318 munmap( mapping->data, mapping->size );
3319 HeapFree( GetProcessHeap(), 0, mapping );
3323 static LONG load_VDMX(GdiFont*, LONG);
3325 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3332 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3336 if (!(font->mapping = map_font_file( face->file )))
3338 WARN("failed to map %s\n", debugstr_a(face->file));
3341 data_ptr = font->mapping->data;
3342 data_size = font->mapping->size;
3346 data_ptr = face->font_data_ptr;
3347 data_size = face->font_data_size;
3350 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3352 ERR("FT_New_Face rets %d\n", err);
3356 /* set it here, as load_VDMX needs it */
3357 font->ft_face = ft_face;
3359 if(FT_IS_SCALABLE(ft_face)) {
3360 /* load the VDMX table if we have one */
3361 font->ppem = load_VDMX(font, height);
3363 font->ppem = calc_ppem_for_height(ft_face, height);
3364 TRACE("height %d => ppem %d\n", height, font->ppem);
3366 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3367 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3369 font->ppem = height;
3370 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3371 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3377 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3379 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3380 a single face with the requested charset. The idea is to check if
3381 the selected font supports the current ANSI codepage, if it does
3382 return the corresponding charset, else return the first charset */
3385 int acp = GetACP(), i;
3389 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3391 const SYSTEM_LINKS *font_link;
3393 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3394 return csi.ciCharset;
3396 font_link = find_font_link(family_name);
3397 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3398 return csi.ciCharset;
3401 for(i = 0; i < 32; i++) {
3403 if(face->fs.fsCsb[0] & fs0) {
3404 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3406 return csi.ciCharset;
3409 FIXME("TCI failing on %x\n", fs0);
3413 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3414 face->fs.fsCsb[0], face->file);
3416 return DEFAULT_CHARSET;
3419 static GdiFont *alloc_font(void)
3421 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3423 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3424 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3426 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3427 ret->total_kern_pairs = (DWORD)-1;
3428 ret->kern_pairs = NULL;
3429 list_init(&ret->hfontlist);
3430 list_init(&ret->child_fonts);
3434 static void free_font(GdiFont *font)
3436 struct list *cursor, *cursor2;
3439 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3441 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3442 list_remove(cursor);
3444 free_font(child->font);
3445 HeapFree(GetProcessHeap(), 0, child);
3448 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3450 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3451 DeleteObject(hfontlist->hfont);
3452 list_remove(&hfontlist->entry);
3453 HeapFree(GetProcessHeap(), 0, hfontlist);
3456 if (font->ft_face) pFT_Done_Face(font->ft_face);
3457 if (font->mapping) unmap_font_file( font->mapping );
3458 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3459 HeapFree(GetProcessHeap(), 0, font->potm);
3460 HeapFree(GetProcessHeap(), 0, font->name);
3461 for (i = 0; i < font->gmsize; i++)
3462 HeapFree(GetProcessHeap(),0,font->gm[i]);
3463 HeapFree(GetProcessHeap(), 0, font->gm);
3464 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3465 HeapFree(GetProcessHeap(), 0, font);
3469 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3471 FT_Face ft_face = font->ft_face;
3475 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3482 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3484 /* make sure value of len is the value freetype says it needs */
3487 FT_ULong needed = 0;
3488 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3489 if( !err && needed < len) len = needed;
3491 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3494 TRACE("Can't find table %c%c%c%c\n",
3495 /* bytes were reversed */
3496 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3497 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3503 /*************************************************************
3506 * load the vdmx entry for the specified height
3509 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3510 ( ( (FT_ULong)_x4 << 24 ) | \
3511 ( (FT_ULong)_x3 << 16 ) | \
3512 ( (FT_ULong)_x2 << 8 ) | \
3515 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3530 static LONG load_VDMX(GdiFont *font, LONG height)
3534 BYTE devXRatio, devYRatio;
3535 USHORT numRecs, numRatios;
3536 DWORD result, offset = -1;
3540 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3542 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3545 /* FIXME: need the real device aspect ratio */
3549 numRecs = GET_BE_WORD(hdr[1]);
3550 numRatios = GET_BE_WORD(hdr[2]);
3552 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3553 for(i = 0; i < numRatios; i++) {
3556 offset = (3 * 2) + (i * sizeof(Ratios));
3557 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3560 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3562 if((ratio.xRatio == 0 &&
3563 ratio.yStartRatio == 0 &&
3564 ratio.yEndRatio == 0) ||
3565 (devXRatio == ratio.xRatio &&
3566 devYRatio >= ratio.yStartRatio &&
3567 devYRatio <= ratio.yEndRatio))
3569 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3570 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3571 offset = GET_BE_WORD(tmp);
3577 FIXME("No suitable ratio found\n");
3581 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3583 BYTE startsz, endsz;
3586 recs = GET_BE_WORD(group.recs);
3587 startsz = group.startsz;
3588 endsz = group.endsz;
3590 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3592 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3593 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3594 if(result == GDI_ERROR) {
3595 FIXME("Failed to retrieve vTable\n");
3600 for(i = 0; i < recs; i++) {
3601 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3602 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3603 ppem = GET_BE_WORD(vTable[i * 3]);
3605 if(yMax + -yMin == height) {
3608 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3611 if(yMax + -yMin > height) {
3614 goto end; /* failed */
3616 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3617 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3618 ppem = GET_BE_WORD(vTable[i * 3]);
3619 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3625 TRACE("ppem not found for height %d\n", height);
3629 HeapFree(GetProcessHeap(), 0, vTable);
3635 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3637 if(font->font_desc.hash != fd->hash) return TRUE;
3638 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3639 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3640 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3641 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3644 static void calc_hash(FONT_DESC *pfd)
3646 DWORD hash = 0, *ptr, two_chars;
3650 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3652 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3654 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3656 pwc = (WCHAR *)&two_chars;
3658 *pwc = toupperW(*pwc);
3660 *pwc = toupperW(*pwc);
3664 hash ^= !pfd->can_use_bitmap;
3669 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3674 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3678 fd.can_use_bitmap = can_use_bitmap;
3681 /* try the child list */
3682 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3683 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3684 if(!fontcmp(ret, &fd)) {
3685 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3686 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3687 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3688 if(hflist->hfont == hfont)
3694 /* try the in-use list */
3695 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3696 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3697 if(!fontcmp(ret, &fd)) {
3698 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3699 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3700 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3701 if(hflist->hfont == hfont)
3704 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3705 hflist->hfont = hfont;
3706 list_add_head(&ret->hfontlist, &hflist->entry);
3711 /* then the unused list */
3712 font_elem_ptr = list_head(&unused_gdi_font_list);
3713 while(font_elem_ptr) {
3714 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3715 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3716 if(!fontcmp(ret, &fd)) {
3717 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3718 assert(list_empty(&ret->hfontlist));
3719 TRACE("Found %p in unused list\n", ret);
3720 list_remove(&ret->entry);
3721 list_add_head(&gdi_font_list, &ret->entry);
3722 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3723 hflist->hfont = hfont;
3724 list_add_head(&ret->hfontlist, &hflist->entry);
3731 static void add_to_cache(GdiFont *font)
3733 static DWORD cache_num = 1;
3735 font->cache_num = cache_num++;
3736 list_add_head(&gdi_font_list, &font->entry);
3739 /*************************************************************
3740 * create_child_font_list
3742 static BOOL create_child_font_list(GdiFont *font)
3745 SYSTEM_LINKS *font_link;
3746 CHILD_FONT *font_link_entry, *new_child;
3750 psub = get_font_subst(&font_subst_list, font->name, -1);
3751 font_name = psub ? psub->to.name : font->name;
3752 font_link = find_font_link(font_name);
3753 if (font_link != NULL)
3755 TRACE("found entry in system list\n");
3756 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3758 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3759 new_child->face = font_link_entry->face;
3760 new_child->font = NULL;
3761 list_add_tail(&font->child_fonts, &new_child->entry);
3762 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3767 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3768 * Sans Serif. This is how asian windows get default fallbacks for fonts
3770 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3771 font->charset != OEM_CHARSET &&
3772 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3774 font_link = find_font_link(szDefaultFallbackLink);
3775 if (font_link != NULL)
3777 TRACE("found entry in default fallback list\n");
3778 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3780 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3781 new_child->face = font_link_entry->face;
3782 new_child->font = NULL;
3783 list_add_tail(&font->child_fonts, &new_child->entry);
3784 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3793 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3795 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3797 if (pFT_Set_Charmap)
3800 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3802 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3804 for (i = 0; i < ft_face->num_charmaps; i++)
3806 if (ft_face->charmaps[i]->encoding == encoding)
3808 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3809 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3811 switch (ft_face->charmaps[i]->platform_id)
3814 cmap_def = ft_face->charmaps[i];
3816 case 0: /* Apple Unicode */
3817 cmap0 = ft_face->charmaps[i];
3819 case 1: /* Macintosh */
3820 cmap1 = ft_face->charmaps[i];
3823 cmap2 = ft_face->charmaps[i];
3825 case 3: /* Microsoft */
3826 cmap3 = ft_face->charmaps[i];
3831 if (cmap3) /* prefer Microsoft cmap table */
3832 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3834 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3836 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3838 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3840 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3842 return ft_err == FT_Err_Ok;
3845 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3849 /*************************************************************
3852 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3853 LPCWSTR output, const DEVMODEW *devmode )
3855 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3857 if (!physdev) return FALSE;
3858 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3863 /*************************************************************
3866 static BOOL freetype_DeleteDC( PHYSDEV dev )
3868 struct freetype_physdev *physdev = get_freetype_dev( dev );
3869 HeapFree( GetProcessHeap(), 0, physdev );
3874 /*************************************************************
3875 * freetype_SelectFont
3877 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3879 struct freetype_physdev *physdev = get_freetype_dev( dev );
3881 Face *face, *best, *best_bitmap;
3882 Family *family, *last_resort_family;
3883 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
3884 INT height, width = 0;
3885 unsigned int score = 0, new_score;
3886 signed int diff = 0, newdiff;
3887 BOOL bd, it, can_use_bitmap, want_vertical;
3892 FontSubst *psub = NULL;
3893 DC *dc = get_dc_ptr( dev->hdc );
3894 const SYSTEM_LINKS *font_link;
3896 if (!hfont) /* notification that the font has been changed by another driver */
3899 physdev->font = NULL;
3900 release_dc_ptr( dc );
3904 GetObjectW( hfont, sizeof(lf), &lf );
3905 lf.lfWidth = abs(lf.lfWidth);
3907 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3909 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3910 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3911 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3914 if(dc->GraphicsMode == GM_ADVANCED)
3916 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3917 /* Try to avoid not necessary glyph transformations */
3918 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3920 lf.lfHeight *= fabs(dcmat.eM11);
3921 lf.lfWidth *= fabs(dcmat.eM11);
3922 dcmat.eM11 = dcmat.eM22 = 1.0;
3927 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3928 font scaling abilities. */
3929 dcmat.eM11 = dcmat.eM22 = 1.0;
3930 dcmat.eM21 = dcmat.eM12 = 0;
3931 if (dc->vport2WorldValid)
3933 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3934 lf.lfOrientation = -lf.lfOrientation;
3935 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3936 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3940 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3941 dcmat.eM21, dcmat.eM22);
3944 EnterCriticalSection( &freetype_cs );
3946 /* check the cache first */
3947 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3948 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3952 if(list_empty(&font_list)) /* No fonts installed */
3954 TRACE("No fonts installed\n");
3958 TRACE("not in cache\n");
3961 ret->font_desc.matrix = dcmat;
3962 ret->font_desc.lf = lf;
3963 ret->font_desc.can_use_bitmap = can_use_bitmap;
3964 calc_hash(&ret->font_desc);
3965 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3966 hflist->hfont = hfont;
3967 list_add_head(&ret->hfontlist, &hflist->entry);
3969 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3970 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3971 original value lfCharSet. Note this is a special case for
3972 Symbol and doesn't happen at least for "Wingdings*" */
3974 if(!strcmpiW(lf.lfFaceName, SymbolW))
3975 lf.lfCharSet = SYMBOL_CHARSET;
3977 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3978 switch(lf.lfCharSet) {
3979 case DEFAULT_CHARSET:
3980 csi.fs.fsCsb[0] = 0;
3983 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3984 csi.fs.fsCsb[0] = 0;
3990 if(lf.lfFaceName[0] != '\0') {
3991 CHILD_FONT *font_link_entry;
3992 LPWSTR FaceName = lf.lfFaceName;
3994 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3997 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3998 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3999 if (psub->to.charset != -1)
4000 lf.lfCharSet = psub->to.charset;
4003 /* We want a match on name and charset or just name if
4004 charset was DEFAULT_CHARSET. If the latter then
4005 we fixup the returned charset later in get_nearest_charset
4006 where we'll either use the charset of the current ansi codepage
4007 or if that's unavailable the first charset that the font supports.
4009 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4010 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4011 if (!strcmpiW(family->FamilyName, FaceName) ||
4012 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4014 font_link = find_font_link(family->FamilyName);
4015 face_list = get_face_list_from_family(family);
4016 LIST_FOR_EACH(face_elem_ptr, face_list) {
4017 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4018 if (!(face->scalable || can_use_bitmap))
4020 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4022 if (font_link != NULL &&
4023 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4025 if (!csi.fs.fsCsb[0])
4031 /* Search by full face name. */
4032 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4033 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4034 face_list = get_face_list_from_family(family);
4035 LIST_FOR_EACH(face_elem_ptr, face_list) {
4036 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4037 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4038 (face->scalable || can_use_bitmap))
4040 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4042 font_link = find_font_link(family->FamilyName);
4043 if (font_link != NULL &&
4044 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4051 * Try check the SystemLink list first for a replacement font.
4052 * We may find good replacements there.
4054 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4056 if(!strcmpiW(font_link->font_name, FaceName) ||
4057 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4059 TRACE("found entry in system list\n");
4060 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4062 const SYSTEM_LINKS *links;
4064 face = font_link_entry->face;
4065 if (!(face->scalable || can_use_bitmap))
4067 family = face->family;
4068 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4070 links = find_font_link(family->FamilyName);
4071 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4078 psub = NULL; /* substitution is no more relevant */
4080 /* If requested charset was DEFAULT_CHARSET then try using charset
4081 corresponding to the current ansi codepage */
4082 if (!csi.fs.fsCsb[0])
4085 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4086 FIXME("TCI failed on codepage %d\n", acp);
4087 csi.fs.fsCsb[0] = 0;
4089 lf.lfCharSet = csi.ciCharset;
4092 want_vertical = (lf.lfFaceName[0] == '@');
4094 /* Face families are in the top 4 bits of lfPitchAndFamily,
4095 so mask with 0xF0 before testing */
4097 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4098 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4099 strcpyW(lf.lfFaceName, defFixed);
4100 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4101 strcpyW(lf.lfFaceName, defSerif);
4102 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4103 strcpyW(lf.lfFaceName, defSans);
4105 strcpyW(lf.lfFaceName, defSans);
4106 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4107 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4108 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4109 font_link = find_font_link(family->FamilyName);
4110 face_list = get_face_list_from_family(family);
4111 LIST_FOR_EACH(face_elem_ptr, face_list) {
4112 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4113 if (!(face->scalable || can_use_bitmap))
4115 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4117 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4123 last_resort_family = NULL;
4124 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4125 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4126 font_link = find_font_link(family->FamilyName);
4127 face_list = get_face_list_from_family(family);
4128 LIST_FOR_EACH(face_elem_ptr, face_list) {
4129 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4130 if(face->vertical == want_vertical &&
4131 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4132 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4135 if(can_use_bitmap && !last_resort_family)
4136 last_resort_family = family;
4141 if(last_resort_family) {
4142 family = last_resort_family;
4143 csi.fs.fsCsb[0] = 0;
4147 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4148 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4149 face_list = get_face_list_from_family(family);
4150 LIST_FOR_EACH(face_elem_ptr, face_list) {
4151 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4152 if(face->scalable && face->vertical == want_vertical) {
4153 csi.fs.fsCsb[0] = 0;
4154 WARN("just using first face for now\n");
4157 if(can_use_bitmap && !last_resort_family)
4158 last_resort_family = family;
4161 if(!last_resort_family) {
4162 FIXME("can't find a single appropriate font - bailing\n");
4168 WARN("could only find a bitmap font - this will probably look awful!\n");
4169 family = last_resort_family;
4170 csi.fs.fsCsb[0] = 0;
4173 it = lf.lfItalic ? 1 : 0;
4174 bd = lf.lfWeight > 550 ? 1 : 0;
4176 height = lf.lfHeight;
4178 face = best = best_bitmap = NULL;
4179 font_link = find_font_link(family->FamilyName);
4180 face_list = get_face_list_from_family(family);
4181 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4183 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4184 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4189 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4190 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4191 new_score = (italic ^ it) + (bold ^ bd);
4192 if(!best || new_score <= score)
4194 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4195 italic, bold, it, bd);
4198 if(best->scalable && score == 0) break;
4202 newdiff = height - (signed int)(best->size.height);
4204 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4205 if(!best_bitmap || new_score < score ||
4206 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4208 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4211 if(score == 0 && diff == 0) break;
4218 face = best->scalable ? best : best_bitmap;
4219 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4220 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4223 height = lf.lfHeight;
4227 if(csi.fs.fsCsb[0]) {
4228 ret->charset = lf.lfCharSet;
4229 ret->codepage = csi.ciACP;
4232 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4234 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4235 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4237 ret->aveWidth = height ? lf.lfWidth : 0;
4239 if(!face->scalable) {
4240 /* Windows uses integer scaling factors for bitmap fonts */
4241 INT scale, scaled_height;
4242 GdiFont *cachedfont;
4244 /* FIXME: rotation of bitmap fonts is ignored */
4245 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4247 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4248 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4249 dcmat.eM11 = dcmat.eM22 = 1.0;
4250 /* As we changed the matrix, we need to search the cache for the font again,
4251 * otherwise we might explode the cache. */
4252 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4253 TRACE("Found cached font after non-scalable matrix rescale!\n");
4258 calc_hash(&ret->font_desc);
4260 if (height != 0) height = diff;
4261 height += face->size.height;
4263 scale = (height + face->size.height - 1) / face->size.height;
4264 scaled_height = scale * face->size.height;
4265 /* Only jump to the next height if the difference <= 25% original height */
4266 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4267 /* The jump between unscaled and doubled is delayed by 1 */
4268 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4269 ret->scale_y = scale;
4271 width = face->size.x_ppem >> 6;
4272 height = face->size.y_ppem >> 6;
4276 TRACE("font scale y: %f\n", ret->scale_y);
4278 ret->ft_face = OpenFontFace(ret, face, width, height);
4287 ret->ntmFlags = face->ntmFlags;
4289 if (ret->charset == SYMBOL_CHARSET &&
4290 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4293 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4297 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4300 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4301 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4302 ret->underline = lf.lfUnderline ? 0xff : 0;
4303 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4304 create_child_font_list(ret);
4306 if (face->vertical) /* We need to try to load the GSUB table */
4308 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4309 if (length != GDI_ERROR)
4311 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4312 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4313 TRACE("Loaded GSUB table of %i bytes\n",length);
4317 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4324 physdev->font = ret;
4326 LeaveCriticalSection( &freetype_cs );
4327 release_dc_ptr( dc );
4328 return ret ? hfont : 0;
4331 static void dump_gdi_font_list(void)
4334 struct list *elem_ptr;
4336 TRACE("---------- gdiFont Cache ----------\n");
4337 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4338 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4339 TRACE("gdiFont=%p %s %d\n",
4340 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4343 TRACE("---------- Unused gdiFont Cache ----------\n");
4344 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4345 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4346 TRACE("gdiFont=%p %s %d\n",
4347 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4350 TRACE("---------- Child gdiFont Cache ----------\n");
4351 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4352 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4353 TRACE("gdiFont=%p %s %d\n",
4354 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4358 /*************************************************************
4359 * WineEngDestroyFontInstance
4361 * free the gdiFont associated with this handle
4364 BOOL WineEngDestroyFontInstance(HFONT handle)
4369 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4373 EnterCriticalSection( &freetype_cs );
4375 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4377 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4378 while(hfontlist_elem_ptr) {
4379 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4380 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4381 if(hflist->hfont == handle) {
4382 TRACE("removing child font %p from child list\n", gdiFont);
4383 list_remove(&gdiFont->entry);
4384 LeaveCriticalSection( &freetype_cs );
4390 TRACE("destroying hfont=%p\n", handle);
4392 dump_gdi_font_list();
4394 font_elem_ptr = list_head(&gdi_font_list);
4395 while(font_elem_ptr) {
4396 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4397 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4399 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4400 while(hfontlist_elem_ptr) {
4401 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4402 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4403 if(hflist->hfont == handle) {
4404 list_remove(&hflist->entry);
4405 HeapFree(GetProcessHeap(), 0, hflist);
4409 if(list_empty(&gdiFont->hfontlist)) {
4410 TRACE("Moving to Unused list\n");
4411 list_remove(&gdiFont->entry);
4412 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4417 font_elem_ptr = list_head(&unused_gdi_font_list);
4418 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4419 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4420 while(font_elem_ptr) {
4421 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4422 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4423 TRACE("freeing %p\n", gdiFont);
4424 list_remove(&gdiFont->entry);
4427 LeaveCriticalSection( &freetype_cs );
4431 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4438 id += IDS_FIRST_SCRIPT;
4439 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4440 if (!rsrc) return 0;
4441 hMem = LoadResource( gdi32_module, rsrc );
4442 if (!hMem) return 0;
4444 p = LockResource( hMem );
4446 while (id--) p += *p + 1;
4448 i = min(LF_FACESIZE - 1, *p);
4449 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4455 /***************************************************
4456 * create_enum_charset_list
4458 * This function creates charset enumeration list because in DEFAULT_CHARSET
4459 * case, the ANSI codepage's charset takes precedence over other charsets.
4460 * This function works as a filter other than DEFAULT_CHARSET case.
4462 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4467 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4468 csi.fs.fsCsb[0] != 0) {
4469 list->element[n].mask = csi.fs.fsCsb[0];
4470 list->element[n].charset = csi.ciCharset;
4471 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4474 else { /* charset is DEFAULT_CHARSET or invalid. */
4477 /* Set the current codepage's charset as the first element. */
4479 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4480 csi.fs.fsCsb[0] != 0) {
4481 list->element[n].mask = csi.fs.fsCsb[0];
4482 list->element[n].charset = csi.ciCharset;
4483 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4487 /* Fill out left elements. */
4488 for (i = 0; i < 32; i++) {
4490 fs.fsCsb[0] = 1L << i;
4492 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4493 continue; /* skip, already added. */
4494 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4495 continue; /* skip, this is an invalid fsCsb bit. */
4497 list->element[n].mask = fs.fsCsb[0];
4498 list->element[n].charset = csi.ciCharset;
4499 load_script_name( i, list->element[n].name );
4508 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4509 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4514 if (face->cached_enum_data)
4517 *pelf = face->cached_enum_data->elf;
4518 *pntm = face->cached_enum_data->ntm;
4519 *ptype = face->cached_enum_data->type;
4523 font = alloc_font();
4525 if(face->scalable) {
4526 height = -2048; /* 2048 is the most common em size */
4529 height = face->size.y_ppem >> 6;
4530 width = face->size.x_ppem >> 6;
4532 font->scale_y = 1.0;
4534 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4540 font->name = strdupW(face->family->FamilyName);
4541 font->ntmFlags = face->ntmFlags;
4543 if (get_outline_text_metrics(font))
4545 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4547 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4549 lstrcpynW(pelf->elfLogFont.lfFaceName,
4550 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4552 lstrcpynW(pelf->elfFullName,
4553 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4555 lstrcpynW(pelf->elfStyle,
4556 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4561 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4563 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4565 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4567 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4569 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4570 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4573 pntm->ntmTm.ntmFlags = face->ntmFlags;
4574 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4575 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4576 pntm->ntmFontSig = face->fs;
4578 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4580 pelf->elfLogFont.lfEscapement = 0;
4581 pelf->elfLogFont.lfOrientation = 0;
4582 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4583 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4584 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4585 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4586 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4587 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4588 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4589 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4590 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4591 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4592 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4595 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4596 *ptype |= TRUETYPE_FONTTYPE;
4597 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4598 *ptype |= DEVICE_FONTTYPE;
4599 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4600 *ptype |= RASTER_FONTTYPE;
4602 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4603 if (face->cached_enum_data)
4605 face->cached_enum_data->elf = *pelf;
4606 face->cached_enum_data->ntm = *pntm;
4607 face->cached_enum_data->type = *ptype;
4613 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
4615 static const WCHAR spaceW[] = { ' ', 0 };
4617 strcpyW(full_name, family_name);
4618 strcatW(full_name, spaceW);
4619 strcatW(full_name, style_name);
4622 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4624 const struct list *face_list, *face_elem_ptr;
4626 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4628 face_list = get_face_list_from_family(family);
4629 LIST_FOR_EACH(face_elem_ptr, face_list)
4631 WCHAR full_family_name[LF_FULLFACESIZE];
4632 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4634 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4636 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4637 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4641 create_full_name(full_family_name, family->FamilyName, face->StyleName);
4642 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4648 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
4650 WCHAR full_family_name[LF_FULLFACESIZE];
4652 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
4654 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4656 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4657 debugstr_w(family_name), debugstr_w(face->StyleName));
4661 create_full_name(full_family_name, family_name, face->StyleName);
4662 return !strcmpiW(lf->lfFaceName, full_family_name);
4665 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
4666 FONTENUMPROCW proc, LPARAM lparam)
4669 NEWTEXTMETRICEXW ntm;
4673 GetEnumStructs(face, &elf, &ntm, &type);
4674 for(i = 0; i < list->total; i++) {
4675 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4676 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4677 load_script_name( IDS_OEM_DOS, elf.elfScript );
4678 i = list->total; /* break out of loop after enumeration */
4679 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4682 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4683 strcpyW(elf.elfScript, list->element[i].name);
4684 if (!elf.elfScript[0])
4685 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4687 /* Font Replacement */
4688 if (family != face->family)
4690 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
4691 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
4693 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4694 debugstr_w(elf.elfLogFont.lfFaceName),
4695 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4696 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4697 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4698 ntm.ntmTm.ntmFlags);
4699 /* release section before callback (FIXME) */
4700 LeaveCriticalSection( &freetype_cs );
4701 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4702 EnterCriticalSection( &freetype_cs );
4707 /*************************************************************
4708 * freetype_EnumFonts
4710 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4714 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4716 struct enum_charset_list enum_charsets;
4720 lf.lfCharSet = DEFAULT_CHARSET;
4721 lf.lfPitchAndFamily = 0;
4722 lf.lfFaceName[0] = 0;
4726 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4728 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4731 EnterCriticalSection( &freetype_cs );
4732 if(plf->lfFaceName[0]) {
4734 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4737 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4738 debugstr_w(psub->to.name));
4740 strcpyW(lf.lfFaceName, psub->to.name);
4744 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4745 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4746 if(family_matches(family, plf)) {
4747 face_list = get_face_list_from_family(family);
4748 LIST_FOR_EACH(face_elem_ptr, face_list) {
4749 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4750 if (!face_matches(family->FamilyName, face, plf)) continue;
4751 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4756 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4757 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4758 face_list = get_face_list_from_family(family);
4759 face_elem_ptr = list_head(face_list);
4760 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4761 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4764 LeaveCriticalSection( &freetype_cs );
4768 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4770 pt->x.value = vec->x >> 6;
4771 pt->x.fract = (vec->x & 0x3f) << 10;
4772 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4773 pt->y.value = vec->y >> 6;
4774 pt->y.fract = (vec->y & 0x3f) << 10;
4775 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4779 /***************************************************
4780 * According to the MSDN documentation on WideCharToMultiByte,
4781 * certain codepages cannot set the default_used parameter.
4782 * This returns TRUE if the codepage can set that parameter, false else
4783 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4785 static BOOL codepage_sets_default_used(UINT codepage)
4799 * GSUB Table handling functions
4802 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4804 const GSUB_CoverageFormat1* cf1;
4808 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4810 int count = GET_BE_WORD(cf1->GlyphCount);
4812 TRACE("Coverage Format 1, %i glyphs\n",count);
4813 for (i = 0; i < count; i++)
4814 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4818 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4820 const GSUB_CoverageFormat2* cf2;
4823 cf2 = (const GSUB_CoverageFormat2*)cf1;
4825 count = GET_BE_WORD(cf2->RangeCount);
4826 TRACE("Coverage Format 2, %i ranges\n",count);
4827 for (i = 0; i < count; i++)
4829 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4831 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4832 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4834 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4835 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4841 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4846 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4848 const GSUB_ScriptList *script;
4849 const GSUB_Script *deflt = NULL;
4851 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4853 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4854 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4856 const GSUB_Script *scr;
4859 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4860 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4862 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4864 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4870 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4874 const GSUB_LangSys *Lang;
4876 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4878 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4880 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4881 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4883 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4886 offset = GET_BE_WORD(script->DefaultLangSys);
4889 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4895 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4898 const GSUB_FeatureList *feature;
4899 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4901 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4902 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4904 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4905 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4907 const GSUB_Feature *feat;
4908 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4915 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4919 const GSUB_LookupList *lookup;
4920 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4922 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4923 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4925 const GSUB_LookupTable *look;
4926 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4927 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4928 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4929 if (GET_BE_WORD(look->LookupType) != 1)
4930 FIXME("We only handle SubType 1\n");
4935 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4937 const GSUB_SingleSubstFormat1 *ssf1;
4938 offset = GET_BE_WORD(look->SubTable[j]);
4939 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4940 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4942 int offset = GET_BE_WORD(ssf1->Coverage);
4943 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4944 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4946 TRACE(" Glyph 0x%x ->",glyph);
4947 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4948 TRACE(" 0x%x\n",glyph);
4953 const GSUB_SingleSubstFormat2 *ssf2;
4957 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4958 offset = GET_BE_WORD(ssf1->Coverage);
4959 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4960 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4961 TRACE(" Coverage index %i\n",index);
4964 TRACE(" Glyph is 0x%x ->",glyph);
4965 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4966 TRACE("0x%x\n",glyph);
4975 static const char* get_opentype_script(const GdiFont *font)
4978 * I am not sure if this is the correct way to generate our script tag
4981 switch (font->charset)
4983 case ANSI_CHARSET: return "latn";
4984 case BALTIC_CHARSET: return "latn"; /* ?? */
4985 case CHINESEBIG5_CHARSET: return "hani";
4986 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4987 case GB2312_CHARSET: return "hani";
4988 case GREEK_CHARSET: return "grek";
4989 case HANGUL_CHARSET: return "hang";
4990 case RUSSIAN_CHARSET: return "cyrl";
4991 case SHIFTJIS_CHARSET: return "kana";
4992 case TURKISH_CHARSET: return "latn"; /* ?? */
4993 case VIETNAMESE_CHARSET: return "latn";
4994 case JOHAB_CHARSET: return "latn"; /* ?? */
4995 case ARABIC_CHARSET: return "arab";
4996 case HEBREW_CHARSET: return "hebr";
4997 case THAI_CHARSET: return "thai";
4998 default: return "latn";
5002 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5004 const GSUB_Header *header;
5005 const GSUB_Script *script;
5006 const GSUB_LangSys *language;
5007 const GSUB_Feature *feature;
5009 if (!font->GSUB_Table)
5012 header = font->GSUB_Table;
5014 script = GSUB_get_script_table(header, get_opentype_script(font));
5017 TRACE("Script not found\n");
5020 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5023 TRACE("Language not found\n");
5026 feature = GSUB_get_feature(header, language, "vrt2");
5028 feature = GSUB_get_feature(header, language, "vert");
5031 TRACE("vrt2/vert feature not found\n");
5034 return GSUB_apply_feature(header, feature, glyph);
5037 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5041 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5042 WCHAR wc = (WCHAR)glyph;
5044 BOOL *default_used_pointer;
5047 default_used_pointer = NULL;
5048 default_used = FALSE;
5049 if (codepage_sets_default_used(font->codepage))
5050 default_used_pointer = &default_used;
5051 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5054 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5055 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5059 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5061 if (glyph < 0x100) glyph += 0xf000;
5062 /* there is a number of old pre-Unicode "broken" TTFs, which
5063 do have symbols at U+00XX instead of U+f0XX */
5064 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5065 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5067 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5072 /*************************************************************
5073 * freetype_GetGlyphIndices
5075 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5077 struct freetype_physdev *physdev = get_freetype_dev( dev );
5080 BOOL got_default = FALSE;
5084 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5085 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5088 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5090 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5095 EnterCriticalSection( &freetype_cs );
5097 for(i = 0; i < count; i++)
5099 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5104 if (FT_IS_SFNT(physdev->font->ft_face))
5106 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5107 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5112 get_text_metrics(physdev->font, &textm);
5113 default_char = textm.tmDefaultChar;
5117 pgi[i] = default_char;
5120 LeaveCriticalSection( &freetype_cs );
5124 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5126 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5127 return !memcmp(matrix, &identity, sizeof(FMAT2));
5130 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5132 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5133 return !memcmp(matrix, &identity, sizeof(MAT2));
5136 static inline BYTE get_max_level( UINT format )
5140 case GGO_GRAY2_BITMAP: return 4;
5141 case GGO_GRAY4_BITMAP: return 16;
5142 case GGO_GRAY8_BITMAP: return 64;
5147 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5149 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5150 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5153 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5154 FT_Face ft_face = incoming_font->ft_face;
5155 GdiFont *font = incoming_font;
5156 FT_UInt glyph_index;
5157 DWORD width, height, pitch, needed = 0;
5158 FT_Bitmap ft_bitmap;
5160 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5162 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5163 double widthRatio = 1.0;
5164 FT_Matrix transMat = identityMat;
5165 FT_Matrix transMatUnrotated;
5166 BOOL needsTransform = FALSE;
5167 BOOL tategaki = (font->GSUB_Table != NULL);
5168 UINT original_index;
5170 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5171 buflen, buf, lpmat);
5173 TRACE("font transform %f %f %f %f\n",
5174 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5175 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5177 if(format & GGO_GLYPH_INDEX) {
5178 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5179 original_index = glyph;
5180 format &= ~GGO_GLYPH_INDEX;
5182 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5183 ft_face = font->ft_face;
5184 original_index = glyph_index;
5187 if(format & GGO_UNHINTED) {
5188 load_flags |= FT_LOAD_NO_HINTING;
5189 format &= ~GGO_UNHINTED;
5192 /* tategaki never appears to happen to lower glyph index */
5193 if (glyph_index < TATEGAKI_LOWER_BOUND )
5196 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5197 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5198 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5199 font->gmsize * sizeof(GM*));
5201 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5202 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5204 *lpgm = FONT_GM(font,original_index)->gm;
5205 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5206 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5207 lpgm->gmCellIncX, lpgm->gmCellIncY);
5208 return 1; /* FIXME */
5212 if (!font->gm[original_index / GM_BLOCK_SIZE])
5213 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5215 /* Scaling factor */
5220 get_text_metrics(font, &tm);
5222 widthRatio = (double)font->aveWidth;
5223 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5226 widthRatio = font->scale_y;
5228 /* Scaling transform */
5229 if (widthRatio != 1.0 || font->scale_y != 1.0)
5232 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5235 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5237 pFT_Matrix_Multiply(&scaleMat, &transMat);
5238 needsTransform = TRUE;
5241 /* Slant transform */
5242 if (font->fake_italic) {
5245 slantMat.xx = (1 << 16);
5246 slantMat.xy = ((1 << 16) >> 2);
5248 slantMat.yy = (1 << 16);
5249 pFT_Matrix_Multiply(&slantMat, &transMat);
5250 needsTransform = TRUE;
5253 /* Rotation transform */
5254 transMatUnrotated = transMat;
5255 if(font->orientation && !tategaki) {
5256 FT_Matrix rotationMat;
5258 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5259 pFT_Vector_Unit(&vecAngle, angle);
5260 rotationMat.xx = vecAngle.x;
5261 rotationMat.xy = -vecAngle.y;
5262 rotationMat.yx = -rotationMat.xy;
5263 rotationMat.yy = rotationMat.xx;
5265 pFT_Matrix_Multiply(&rotationMat, &transMat);
5266 needsTransform = TRUE;
5269 /* World transform */
5270 if (!is_identity_FMAT2(&font->font_desc.matrix))
5273 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5274 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5275 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5276 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5277 pFT_Matrix_Multiply(&worldMat, &transMat);
5278 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5279 needsTransform = TRUE;
5282 /* Extra transformation specified by caller */
5283 if (!is_identity_MAT2(lpmat))
5286 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5287 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5288 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5289 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5290 pFT_Matrix_Multiply(&extraMat, &transMat);
5291 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5292 needsTransform = TRUE;
5295 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5296 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5297 format == GGO_GRAY8_BITMAP))
5299 load_flags |= FT_LOAD_NO_BITMAP;
5302 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5305 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5309 if(!needsTransform) {
5310 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5311 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5312 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5314 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5315 bottom = (ft_face->glyph->metrics.horiBearingY -
5316 ft_face->glyph->metrics.height) & -64;
5317 lpgm->gmCellIncX = adv;
5318 lpgm->gmCellIncY = 0;
5325 for(xc = 0; xc < 2; xc++) {
5326 for(yc = 0; yc < 2; yc++) {
5327 vec.x = (ft_face->glyph->metrics.horiBearingX +
5328 xc * ft_face->glyph->metrics.width);
5329 vec.y = ft_face->glyph->metrics.horiBearingY -
5330 yc * ft_face->glyph->metrics.height;
5331 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5332 pFT_Vector_Transform(&vec, &transMat);
5333 if(xc == 0 && yc == 0) {
5334 left = right = vec.x;
5335 top = bottom = vec.y;
5337 if(vec.x < left) left = vec.x;
5338 else if(vec.x > right) right = vec.x;
5339 if(vec.y < bottom) bottom = vec.y;
5340 else if(vec.y > top) top = vec.y;
5345 right = (right + 63) & -64;
5346 bottom = bottom & -64;
5347 top = (top + 63) & -64;
5349 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5350 vec.x = ft_face->glyph->metrics.horiAdvance;
5352 pFT_Vector_Transform(&vec, &transMat);
5353 lpgm->gmCellIncX = (vec.x+63) >> 6;
5354 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5356 vec.x = ft_face->glyph->metrics.horiAdvance;
5358 pFT_Vector_Transform(&vec, &transMatUnrotated);
5359 adv = (vec.x+63) >> 6;
5363 bbx = (right - left) >> 6;
5364 lpgm->gmBlackBoxX = (right - left) >> 6;
5365 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5366 lpgm->gmptGlyphOrigin.x = left >> 6;
5367 lpgm->gmptGlyphOrigin.y = top >> 6;
5369 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5370 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5371 lpgm->gmCellIncX, lpgm->gmCellIncY);
5373 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5374 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5376 FONT_GM(font,original_index)->gm = *lpgm;
5377 FONT_GM(font,original_index)->adv = adv;
5378 FONT_GM(font,original_index)->lsb = lsb;
5379 FONT_GM(font,original_index)->bbx = bbx;
5380 FONT_GM(font,original_index)->init = TRUE;
5383 if(format == GGO_METRICS)
5385 return 1; /* FIXME */
5388 if(ft_face->glyph->format != ft_glyph_format_outline &&
5389 (format == GGO_NATIVE || format == GGO_BEZIER))
5391 TRACE("loaded a bitmap\n");
5397 width = lpgm->gmBlackBoxX;
5398 height = lpgm->gmBlackBoxY;
5399 pitch = ((width + 31) >> 5) << 2;
5400 needed = pitch * height;
5402 if(!buf || !buflen) break;
5404 switch(ft_face->glyph->format) {
5405 case ft_glyph_format_bitmap:
5407 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5408 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5409 INT h = ft_face->glyph->bitmap.rows;
5411 memcpy(dst, src, w);
5412 src += ft_face->glyph->bitmap.pitch;
5418 case ft_glyph_format_outline:
5419 ft_bitmap.width = width;
5420 ft_bitmap.rows = height;
5421 ft_bitmap.pitch = pitch;
5422 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5423 ft_bitmap.buffer = buf;
5426 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5428 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5430 /* Note: FreeType will only set 'black' bits for us. */
5431 memset(buf, 0, needed);
5432 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5436 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5441 case GGO_GRAY2_BITMAP:
5442 case GGO_GRAY4_BITMAP:
5443 case GGO_GRAY8_BITMAP:
5444 case WINE_GGO_GRAY16_BITMAP:
5446 unsigned int max_level, row, col;
5449 width = lpgm->gmBlackBoxX;
5450 height = lpgm->gmBlackBoxY;
5451 pitch = (width + 3) / 4 * 4;
5452 needed = pitch * height;
5454 if(!buf || !buflen) break;
5456 max_level = get_max_level( format );
5458 switch(ft_face->glyph->format) {
5459 case ft_glyph_format_bitmap:
5461 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5462 INT h = ft_face->glyph->bitmap.rows;
5464 memset( buf, 0, needed );
5466 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5467 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5468 src += ft_face->glyph->bitmap.pitch;
5473 case ft_glyph_format_outline:
5475 ft_bitmap.width = width;
5476 ft_bitmap.rows = height;
5477 ft_bitmap.pitch = pitch;
5478 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5479 ft_bitmap.buffer = buf;
5482 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5484 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5486 memset(ft_bitmap.buffer, 0, buflen);
5488 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5490 if (max_level != 255)
5492 for (row = 0, start = buf; row < height; row++)
5494 for (col = 0, ptr = start; col < width; col++, ptr++)
5495 *ptr = (((int)*ptr) * max_level + 128) / 256;
5503 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5509 case WINE_GGO_HRGB_BITMAP:
5510 case WINE_GGO_HBGR_BITMAP:
5511 case WINE_GGO_VRGB_BITMAP:
5512 case WINE_GGO_VBGR_BITMAP:
5513 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5515 switch (ft_face->glyph->format)
5517 case FT_GLYPH_FORMAT_BITMAP:
5522 width = lpgm->gmBlackBoxX;
5523 height = lpgm->gmBlackBoxY;
5525 needed = pitch * height;
5527 if (!buf || !buflen) break;
5529 memset(buf, 0, buflen);
5531 src = ft_face->glyph->bitmap.buffer;
5532 src_pitch = ft_face->glyph->bitmap.pitch;
5534 height = min( height, ft_face->glyph->bitmap.rows );
5537 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5539 if ( src[x / 8] & masks[x % 8] )
5540 ((unsigned int *)dst)[x] = ~0u;
5549 case FT_GLYPH_FORMAT_OUTLINE:
5553 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5554 INT x_shift, y_shift;
5556 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5557 FT_Render_Mode render_mode =
5558 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5559 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5561 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5563 if ( render_mode == FT_RENDER_MODE_LCD)
5565 lpgm->gmBlackBoxX += 2;
5566 lpgm->gmptGlyphOrigin.x -= 1;
5570 lpgm->gmBlackBoxY += 2;
5571 lpgm->gmptGlyphOrigin.y += 1;
5575 width = lpgm->gmBlackBoxX;
5576 height = lpgm->gmBlackBoxY;
5578 needed = pitch * height;
5580 if (!buf || !buflen) break;
5582 memset(buf, 0, buflen);
5584 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5586 if ( needsTransform )
5587 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5589 if ( pFT_Library_SetLcdFilter )
5590 pFT_Library_SetLcdFilter( library, lcdfilter );
5591 pFT_Render_Glyph (ft_face->glyph, render_mode);
5593 src = ft_face->glyph->bitmap.buffer;
5594 src_pitch = ft_face->glyph->bitmap.pitch;
5595 src_width = ft_face->glyph->bitmap.width;
5596 src_height = ft_face->glyph->bitmap.rows;
5598 if ( render_mode == FT_RENDER_MODE_LCD)
5606 rgb_interval = src_pitch;
5611 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5612 if ( x_shift < 0 ) x_shift = 0;
5613 if ( x_shift + (src_width / hmul) > width )
5614 x_shift = width - (src_width / hmul);
5616 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5617 if ( y_shift < 0 ) y_shift = 0;
5618 if ( y_shift + (src_height / vmul) > height )
5619 y_shift = height - (src_height / vmul);
5621 dst += x_shift + y_shift * ( pitch / 4 );
5622 while ( src_height )
5624 for ( x = 0; x < src_width / hmul; x++ )
5628 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5629 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5630 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5631 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5635 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5636 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5637 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5638 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5641 src += src_pitch * vmul;
5650 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5662 int contour, point = 0, first_pt;
5663 FT_Outline *outline = &ft_face->glyph->outline;
5664 TTPOLYGONHEADER *pph;
5666 DWORD pph_start, cpfx, type;
5668 if(buflen == 0) buf = NULL;
5670 if (needsTransform && buf) {
5671 pFT_Outline_Transform(outline, &transMat);
5674 for(contour = 0; contour < outline->n_contours; contour++) {
5676 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5679 pph->dwType = TT_POLYGON_TYPE;
5680 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5682 needed += sizeof(*pph);
5684 while(point <= outline->contours[contour]) {
5685 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5686 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5687 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5691 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5694 } while(point <= outline->contours[contour] &&
5695 (outline->tags[point] & FT_Curve_Tag_On) ==
5696 (outline->tags[point-1] & FT_Curve_Tag_On));
5697 /* At the end of a contour Windows adds the start point, but
5699 if(point > outline->contours[contour] &&
5700 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5702 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5704 } else if(point <= outline->contours[contour] &&
5705 outline->tags[point] & FT_Curve_Tag_On) {
5706 /* add closing pt for bezier */
5708 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5716 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5719 pph->cb = needed - pph_start;
5725 /* Convert the quadratic Beziers to cubic Beziers.
5726 The parametric eqn for a cubic Bezier is, from PLRM:
5727 r(t) = at^3 + bt^2 + ct + r0
5728 with the control points:
5733 A quadratic Bezier has the form:
5734 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5736 So equating powers of t leads to:
5737 r1 = 2/3 p1 + 1/3 p0
5738 r2 = 2/3 p1 + 1/3 p2
5739 and of course r0 = p0, r3 = p2
5742 int contour, point = 0, first_pt;
5743 FT_Outline *outline = &ft_face->glyph->outline;
5744 TTPOLYGONHEADER *pph;
5746 DWORD pph_start, cpfx, type;
5747 FT_Vector cubic_control[4];
5748 if(buflen == 0) buf = NULL;
5750 if (needsTransform && buf) {
5751 pFT_Outline_Transform(outline, &transMat);
5754 for(contour = 0; contour < outline->n_contours; contour++) {
5756 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5759 pph->dwType = TT_POLYGON_TYPE;
5760 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5762 needed += sizeof(*pph);
5764 while(point <= outline->contours[contour]) {
5765 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5766 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5767 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5770 if(type == TT_PRIM_LINE) {
5772 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5776 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5779 /* FIXME: Possible optimization in endpoint calculation
5780 if there are two consecutive curves */
5781 cubic_control[0] = outline->points[point-1];
5782 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5783 cubic_control[0].x += outline->points[point].x + 1;
5784 cubic_control[0].y += outline->points[point].y + 1;
5785 cubic_control[0].x >>= 1;
5786 cubic_control[0].y >>= 1;
5788 if(point+1 > outline->contours[contour])
5789 cubic_control[3] = outline->points[first_pt];
5791 cubic_control[3] = outline->points[point+1];
5792 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5793 cubic_control[3].x += outline->points[point].x + 1;
5794 cubic_control[3].y += outline->points[point].y + 1;
5795 cubic_control[3].x >>= 1;
5796 cubic_control[3].y >>= 1;
5799 /* r1 = 1/3 p0 + 2/3 p1
5800 r2 = 1/3 p2 + 2/3 p1 */
5801 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5802 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5803 cubic_control[2] = cubic_control[1];
5804 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5805 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5806 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5807 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5809 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5810 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5811 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5816 } while(point <= outline->contours[contour] &&
5817 (outline->tags[point] & FT_Curve_Tag_On) ==
5818 (outline->tags[point-1] & FT_Curve_Tag_On));
5819 /* At the end of a contour Windows adds the start point,
5820 but only for Beziers and we've already done that.
5822 if(point <= outline->contours[contour] &&
5823 outline->tags[point] & FT_Curve_Tag_On) {
5824 /* This is the closing pt of a bezier, but we've already
5825 added it, so just inc point and carry on */
5832 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5835 pph->cb = needed - pph_start;
5841 FIXME("Unsupported format %d\n", format);
5847 static BOOL get_bitmap_text_metrics(GdiFont *font)
5849 FT_Face ft_face = font->ft_face;
5850 FT_WinFNT_HeaderRec winfnt_header;
5851 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5852 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5853 font->potm->otmSize = size;
5855 #define TM font->potm->otmTextMetrics
5856 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5858 TM.tmHeight = winfnt_header.pixel_height;
5859 TM.tmAscent = winfnt_header.ascent;
5860 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5861 TM.tmInternalLeading = winfnt_header.internal_leading;
5862 TM.tmExternalLeading = winfnt_header.external_leading;
5863 TM.tmAveCharWidth = winfnt_header.avg_width;
5864 TM.tmMaxCharWidth = winfnt_header.max_width;
5865 TM.tmWeight = winfnt_header.weight;
5867 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5868 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5869 TM.tmFirstChar = winfnt_header.first_char;
5870 TM.tmLastChar = winfnt_header.last_char;
5871 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5872 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5873 TM.tmItalic = winfnt_header.italic;
5874 TM.tmUnderlined = font->underline;
5875 TM.tmStruckOut = font->strikeout;
5876 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5877 TM.tmCharSet = winfnt_header.charset;
5881 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5882 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5883 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5884 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5885 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5886 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5887 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5888 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5890 TM.tmDigitizedAspectX = 96; /* FIXME */
5891 TM.tmDigitizedAspectY = 96; /* FIXME */
5893 TM.tmLastChar = 255;
5894 TM.tmDefaultChar = 32;
5895 TM.tmBreakChar = 32;
5896 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5897 TM.tmUnderlined = font->underline;
5898 TM.tmStruckOut = font->strikeout;
5899 /* NB inverted meaning of TMPF_FIXED_PITCH */
5900 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5901 TM.tmCharSet = font->charset;
5909 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5911 double scale_x, scale_y;
5915 scale_x = (double)font->aveWidth;
5916 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5919 scale_x = font->scale_y;
5921 scale_x *= fabs(font->font_desc.matrix.eM11);
5922 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5924 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5925 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5927 SCALE_Y(ptm->tmHeight);
5928 SCALE_Y(ptm->tmAscent);
5929 SCALE_Y(ptm->tmDescent);
5930 SCALE_Y(ptm->tmInternalLeading);
5931 SCALE_Y(ptm->tmExternalLeading);
5932 SCALE_Y(ptm->tmOverhang);
5934 SCALE_X(ptm->tmAveCharWidth);
5935 SCALE_X(ptm->tmMaxCharWidth);
5941 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5943 double scale_x, scale_y;
5947 scale_x = (double)font->aveWidth;
5948 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5951 scale_x = font->scale_y;
5953 scale_x *= fabs(font->font_desc.matrix.eM11);
5954 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5956 scale_font_metrics(font, &potm->otmTextMetrics);
5958 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5959 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5961 SCALE_Y(potm->otmAscent);
5962 SCALE_Y(potm->otmDescent);
5963 SCALE_Y(potm->otmLineGap);
5964 SCALE_Y(potm->otmsCapEmHeight);
5965 SCALE_Y(potm->otmsXHeight);
5966 SCALE_Y(potm->otmrcFontBox.top);
5967 SCALE_Y(potm->otmrcFontBox.bottom);
5968 SCALE_X(potm->otmrcFontBox.left);
5969 SCALE_X(potm->otmrcFontBox.right);
5970 SCALE_Y(potm->otmMacAscent);
5971 SCALE_Y(potm->otmMacDescent);
5972 SCALE_Y(potm->otmMacLineGap);
5973 SCALE_X(potm->otmptSubscriptSize.x);
5974 SCALE_Y(potm->otmptSubscriptSize.y);
5975 SCALE_X(potm->otmptSubscriptOffset.x);
5976 SCALE_Y(potm->otmptSubscriptOffset.y);
5977 SCALE_X(potm->otmptSuperscriptSize.x);
5978 SCALE_Y(potm->otmptSuperscriptSize.y);
5979 SCALE_X(potm->otmptSuperscriptOffset.x);
5980 SCALE_Y(potm->otmptSuperscriptOffset.y);
5981 SCALE_Y(potm->otmsStrikeoutSize);
5982 SCALE_Y(potm->otmsStrikeoutPosition);
5983 SCALE_Y(potm->otmsUnderscoreSize);
5984 SCALE_Y(potm->otmsUnderscorePosition);
5990 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5994 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5996 /* Make sure that the font has sane width/height ratio */
5999 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6001 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6006 *ptm = font->potm->otmTextMetrics;
6007 scale_font_metrics(font, ptm);
6011 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6015 for(i = 0; i < ft_face->num_charmaps; i++)
6017 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6023 static BOOL get_outline_text_metrics(GdiFont *font)
6026 FT_Face ft_face = font->ft_face;
6027 UINT needed, lenfam, lensty;
6029 TT_HoriHeader *pHori;
6030 TT_Postscript *pPost;
6031 FT_Fixed x_scale, y_scale;
6032 WCHAR *family_nameW, *style_nameW;
6033 static const WCHAR spaceW[] = {' ', '\0'};
6035 INT ascent, descent;
6037 TRACE("font=%p\n", font);
6039 if(!FT_IS_SCALABLE(ft_face))
6042 needed = sizeof(*font->potm);
6044 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6045 family_nameW = strdupW(font->name);
6047 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6049 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6050 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6051 style_nameW, lensty/sizeof(WCHAR));
6053 /* These names should be read from the TT name table */
6055 /* length of otmpFamilyName */
6058 /* length of otmpFaceName */
6059 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6060 needed += lenfam; /* just the family name */
6062 needed += lenfam + lensty; /* family + " " + style */
6065 /* length of otmpStyleName */
6068 /* length of otmpFullName */
6069 needed += lenfam + lensty;
6072 x_scale = ft_face->size->metrics.x_scale;
6073 y_scale = ft_face->size->metrics.y_scale;
6075 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6077 FIXME("Can't find OS/2 table - not TT font?\n");
6081 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6083 FIXME("Can't find HHEA table - not TT font?\n");
6087 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6089 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",
6090 pOS2->usWinAscent, pOS2->usWinDescent,
6091 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6092 ft_face->ascender, ft_face->descender, ft_face->height,
6093 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6094 ft_face->bbox.yMax, ft_face->bbox.yMin);
6096 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6097 font->potm->otmSize = needed;
6099 #define TM font->potm->otmTextMetrics
6101 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6102 ascent = pHori->Ascender;
6103 descent = -pHori->Descender;
6105 ascent = pOS2->usWinAscent;
6106 descent = pOS2->usWinDescent;
6110 TM.tmAscent = font->yMax;
6111 TM.tmDescent = -font->yMin;
6112 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6114 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6115 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6116 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6117 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6120 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6123 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6125 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6126 ((ascent + descent) -
6127 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6129 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6130 if (TM.tmAveCharWidth == 0) {
6131 TM.tmAveCharWidth = 1;
6133 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6134 TM.tmWeight = FW_REGULAR;
6135 if (font->fake_bold)
6136 TM.tmWeight = FW_BOLD;
6139 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6141 if (pOS2->usWeightClass > FW_MEDIUM)
6142 TM.tmWeight = pOS2->usWeightClass;
6144 else if (pOS2->usWeightClass <= FW_MEDIUM)
6145 TM.tmWeight = pOS2->usWeightClass;
6148 TM.tmDigitizedAspectX = 300;
6149 TM.tmDigitizedAspectY = 300;
6150 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6151 * symbol range to 0 - f0ff
6154 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6159 case 1257: /* Baltic */
6160 TM.tmLastChar = 0xf8fd;
6163 TM.tmLastChar = 0xf0ff;
6165 TM.tmBreakChar = 0x20;
6166 TM.tmDefaultChar = 0x1f;
6170 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6171 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6173 if(pOS2->usFirstCharIndex <= 1)
6174 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6175 else if (pOS2->usFirstCharIndex > 0xff)
6176 TM.tmBreakChar = 0x20;
6178 TM.tmBreakChar = pOS2->usFirstCharIndex;
6179 TM.tmDefaultChar = TM.tmBreakChar - 1;
6181 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6182 TM.tmUnderlined = font->underline;
6183 TM.tmStruckOut = font->strikeout;
6185 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6186 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6187 (pOS2->version == 0xFFFFU ||
6188 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6189 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6191 TM.tmPitchAndFamily = 0;
6193 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6195 case PAN_FAMILY_SCRIPT:
6196 TM.tmPitchAndFamily |= FF_SCRIPT;
6199 case PAN_FAMILY_DECORATIVE:
6200 TM.tmPitchAndFamily |= FF_DECORATIVE;
6205 case PAN_FAMILY_TEXT_DISPLAY:
6206 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6207 /* which is clearly not what the panose spec says. */
6209 if(TM.tmPitchAndFamily == 0 || /* fixed */
6210 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6211 TM.tmPitchAndFamily = FF_MODERN;
6214 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6219 TM.tmPitchAndFamily |= FF_DONTCARE;
6222 case PAN_SERIF_COVE:
6223 case PAN_SERIF_OBTUSE_COVE:
6224 case PAN_SERIF_SQUARE_COVE:
6225 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6226 case PAN_SERIF_SQUARE:
6227 case PAN_SERIF_THIN:
6228 case PAN_SERIF_BONE:
6229 case PAN_SERIF_EXAGGERATED:
6230 case PAN_SERIF_TRIANGLE:
6231 TM.tmPitchAndFamily |= FF_ROMAN;
6234 case PAN_SERIF_NORMAL_SANS:
6235 case PAN_SERIF_OBTUSE_SANS:
6236 case PAN_SERIF_PERP_SANS:
6237 case PAN_SERIF_FLARED:
6238 case PAN_SERIF_ROUNDED:
6239 TM.tmPitchAndFamily |= FF_SWISS;
6246 if(FT_IS_SCALABLE(ft_face))
6247 TM.tmPitchAndFamily |= TMPF_VECTOR;
6249 if(FT_IS_SFNT(ft_face))
6251 if (font->ntmFlags & NTM_PS_OPENTYPE)
6252 TM.tmPitchAndFamily |= TMPF_DEVICE;
6254 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6257 TM.tmCharSet = font->charset;
6259 font->potm->otmFiller = 0;
6260 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6261 font->potm->otmfsSelection = pOS2->fsSelection;
6262 font->potm->otmfsType = pOS2->fsType;
6263 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6264 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6265 font->potm->otmItalicAngle = 0; /* POST table */
6266 font->potm->otmEMSquare = ft_face->units_per_EM;
6267 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6268 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6269 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6270 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6271 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6272 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6273 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6274 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6275 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6276 font->potm->otmMacAscent = TM.tmAscent;
6277 font->potm->otmMacDescent = -TM.tmDescent;
6278 font->potm->otmMacLineGap = font->potm->otmLineGap;
6279 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6280 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6281 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6282 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6283 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6284 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6285 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6286 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6287 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6288 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6289 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6291 font->potm->otmsUnderscoreSize = 0;
6292 font->potm->otmsUnderscorePosition = 0;
6294 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6295 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6299 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6300 cp = (char*)font->potm + sizeof(*font->potm);
6301 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6302 strcpyW((WCHAR*)cp, family_nameW);
6304 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6305 strcpyW((WCHAR*)cp, style_nameW);
6307 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6308 strcpyW((WCHAR*)cp, family_nameW);
6309 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6310 strcatW((WCHAR*)cp, spaceW);
6311 strcatW((WCHAR*)cp, style_nameW);
6312 cp += lenfam + lensty;
6315 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6316 strcpyW((WCHAR*)cp, family_nameW);
6317 strcatW((WCHAR*)cp, spaceW);
6318 strcatW((WCHAR*)cp, style_nameW);
6322 HeapFree(GetProcessHeap(), 0, style_nameW);
6323 HeapFree(GetProcessHeap(), 0, family_nameW);
6327 /*************************************************************
6328 * freetype_GetGlyphOutline
6330 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6331 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6333 struct freetype_physdev *physdev = get_freetype_dev( dev );
6338 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6339 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6343 EnterCriticalSection( &freetype_cs );
6344 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6345 LeaveCriticalSection( &freetype_cs );
6349 /*************************************************************
6350 * freetype_GetTextMetrics
6352 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6354 struct freetype_physdev *physdev = get_freetype_dev( dev );
6359 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6360 return dev->funcs->pGetTextMetrics( dev, metrics );
6364 EnterCriticalSection( &freetype_cs );
6365 ret = get_text_metrics( physdev->font, metrics );
6366 LeaveCriticalSection( &freetype_cs );
6370 /*************************************************************
6371 * freetype_GetOutlineTextMetrics
6373 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6375 struct freetype_physdev *physdev = get_freetype_dev( dev );
6380 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6381 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6384 TRACE("font=%p\n", physdev->font);
6386 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6389 EnterCriticalSection( &freetype_cs );
6391 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6393 if(cbSize >= physdev->font->potm->otmSize)
6395 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6396 scale_outline_font_metrics(physdev->font, potm);
6398 ret = physdev->font->potm->otmSize;
6400 LeaveCriticalSection( &freetype_cs );
6404 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6406 HFONTLIST *hfontlist;
6407 child->font = alloc_font();
6408 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6409 if(!child->font->ft_face)
6411 free_font(child->font);
6416 child->font->font_desc = font->font_desc;
6417 child->font->ntmFlags = child->face->ntmFlags;
6418 child->font->orientation = font->orientation;
6419 child->font->scale_y = font->scale_y;
6420 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6421 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6422 child->font->name = strdupW(child->face->family->FamilyName);
6423 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6424 child->font->base_font = font;
6425 list_add_head(&child_font_list, &child->font->entry);
6426 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6430 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6433 CHILD_FONT *child_font;
6436 font = font->base_font;
6438 *linked_font = font;
6440 if((*glyph = get_glyph_index(font, c)))
6442 *glyph = get_GSUB_vert_glyph(font, *glyph);
6446 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6448 if(!child_font->font)
6449 if(!load_child_font(font, child_font))
6452 if(!child_font->font->ft_face)
6454 g = get_glyph_index(child_font->font, c);
6455 g = get_GSUB_vert_glyph(child_font->font, g);
6459 *linked_font = child_font->font;
6466 /*************************************************************
6467 * freetype_GetCharWidth
6469 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6471 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6474 FT_UInt glyph_index;
6475 GdiFont *linked_font;
6476 struct freetype_physdev *physdev = get_freetype_dev( dev );
6480 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6481 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6484 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6487 EnterCriticalSection( &freetype_cs );
6488 for(c = firstChar; c <= lastChar; c++) {
6489 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6490 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6491 &gm, 0, NULL, &identity);
6492 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6494 LeaveCriticalSection( &freetype_cs );
6498 /*************************************************************
6499 * freetype_GetCharABCWidths
6501 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6503 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6506 FT_UInt glyph_index;
6507 GdiFont *linked_font;
6508 struct freetype_physdev *physdev = get_freetype_dev( dev );
6512 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6513 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6516 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6519 EnterCriticalSection( &freetype_cs );
6521 for(c = firstChar; c <= lastChar; c++) {
6522 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6523 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6524 &gm, 0, NULL, &identity);
6525 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6526 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6527 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6528 FONT_GM(linked_font,glyph_index)->bbx;
6530 LeaveCriticalSection( &freetype_cs );
6534 /*************************************************************
6535 * freetype_GetCharABCWidthsI
6537 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6539 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6542 FT_UInt glyph_index;
6543 GdiFont *linked_font;
6544 struct freetype_physdev *physdev = get_freetype_dev( dev );
6548 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6549 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6552 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6556 EnterCriticalSection( &freetype_cs );
6558 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6560 for(c = firstChar; c < firstChar+count; c++) {
6561 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6562 &gm, 0, NULL, &identity);
6563 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6564 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6565 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6566 - FONT_GM(linked_font,c)->bbx;
6569 for(c = 0; c < count; c++) {
6570 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6571 &gm, 0, NULL, &identity);
6572 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6573 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6574 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6575 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6578 LeaveCriticalSection( &freetype_cs );
6582 /*************************************************************
6583 * freetype_GetTextExtentExPoint
6585 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6586 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6588 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6593 FT_UInt glyph_index;
6594 GdiFont *linked_font;
6595 struct freetype_physdev *physdev = get_freetype_dev( dev );
6599 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6600 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6603 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6606 EnterCriticalSection( &freetype_cs );
6609 get_text_metrics( physdev->font, &tm );
6610 size->cy = tm.tmHeight;
6612 for(idx = 0; idx < count; idx++) {
6613 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6614 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6615 &gm, 0, NULL, &identity);
6616 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6618 if (! pnfit || ext <= max_ext) {
6628 LeaveCriticalSection( &freetype_cs );
6629 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6633 /*************************************************************
6634 * freetype_GetTextExtentExPointI
6636 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6637 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6639 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6644 struct freetype_physdev *physdev = get_freetype_dev( dev );
6648 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6649 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6652 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6655 EnterCriticalSection( &freetype_cs );
6658 get_text_metrics(physdev->font, &tm);
6659 size->cy = tm.tmHeight;
6661 for(idx = 0; idx < count; idx++) {
6662 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6663 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6665 if (! pnfit || ext <= max_ext) {
6675 LeaveCriticalSection( &freetype_cs );
6676 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6680 /*************************************************************
6681 * freetype_GetFontData
6683 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6685 struct freetype_physdev *physdev = get_freetype_dev( dev );
6689 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6690 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6693 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6694 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6695 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6697 return get_font_data( physdev->font, table, offset, buf, cbData );
6700 /*************************************************************
6701 * freetype_GetTextFace
6703 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6706 struct freetype_physdev *physdev = get_freetype_dev( dev );
6710 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6711 return dev->funcs->pGetTextFace( dev, count, str );
6714 n = strlenW(physdev->font->name) + 1;
6717 lstrcpynW(str, physdev->font->name, count);
6723 /*************************************************************
6724 * freetype_GetTextCharsetInfo
6726 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6728 struct freetype_physdev *physdev = get_freetype_dev( dev );
6732 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6733 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6735 if (fs) *fs = physdev->font->fs;
6736 return physdev->font->charset;
6739 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6741 GdiFont *font = dc->gdiFont, *linked_font;
6742 struct list *first_hfont;
6746 EnterCriticalSection( &freetype_cs );
6747 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6748 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6749 if(font == linked_font)
6750 *new_hfont = dc->hFont;
6753 first_hfont = list_head(&linked_font->hfontlist);
6754 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6756 LeaveCriticalSection( &freetype_cs );
6760 /* Retrieve a list of supported Unicode ranges for a given font.
6761 * Can be called with NULL gs to calculate the buffer size. Returns
6762 * the number of ranges found.
6764 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6766 DWORD num_ranges = 0;
6768 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6771 FT_ULong char_code, char_code_prev;
6774 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6776 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6777 face->num_glyphs, glyph_code, char_code);
6779 if (!glyph_code) return 0;
6783 gs->ranges[0].wcLow = (USHORT)char_code;
6784 gs->ranges[0].cGlyphs = 0;
6785 gs->cGlyphsSupported = 0;
6791 if (char_code < char_code_prev)
6793 ERR("expected increasing char code from FT_Get_Next_Char\n");
6796 if (char_code - char_code_prev > 1)
6801 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6802 gs->ranges[num_ranges - 1].cGlyphs = 1;
6803 gs->cGlyphsSupported++;
6808 gs->ranges[num_ranges - 1].cGlyphs++;
6809 gs->cGlyphsSupported++;
6811 char_code_prev = char_code;
6812 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6816 FIXME("encoding %u not supported\n", face->charmap->encoding);
6821 /*************************************************************
6822 * freetype_GetFontUnicodeRanges
6824 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6826 struct freetype_physdev *physdev = get_freetype_dev( dev );
6827 DWORD size, num_ranges;
6831 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6832 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6835 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6836 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6839 glyphset->cbThis = size;
6840 glyphset->cRanges = num_ranges;
6841 glyphset->flAccel = 0;
6846 /*************************************************************
6847 * freetype_FontIsLinked
6849 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6851 struct freetype_physdev *physdev = get_freetype_dev( dev );
6856 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6857 return dev->funcs->pFontIsLinked( dev );
6861 EnterCriticalSection( &freetype_cs );
6862 ret = !list_empty(&physdev->font->child_fonts);
6863 LeaveCriticalSection( &freetype_cs );
6867 static BOOL is_hinting_enabled(void)
6869 /* Use the >= 2.2.0 function if available */
6870 if(pFT_Get_TrueType_Engine_Type)
6872 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6873 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6875 #ifdef FT_DRIVER_HAS_HINTER
6880 /* otherwise if we've been compiled with < 2.2.0 headers
6881 use the internal macro */
6882 mod = pFT_Get_Module(library, "truetype");
6883 if(mod && FT_DRIVER_HAS_HINTER(mod))
6891 static BOOL is_subpixel_rendering_enabled( void )
6893 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6894 return pFT_Library_SetLcdFilter &&
6895 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6901 /*************************************************************************
6902 * GetRasterizerCaps (GDI32.@)
6904 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6906 static int hinting = -1;
6907 static int subpixel = -1;
6911 hinting = is_hinting_enabled();
6912 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6915 if ( subpixel == -1 )
6917 subpixel = is_subpixel_rendering_enabled();
6918 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6921 lprs->nSize = sizeof(RASTERIZER_STATUS);
6922 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6924 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6925 lprs->nLanguageID = 0;
6929 /*************************************************************
6930 * freetype_GdiRealizationInfo
6932 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6934 struct freetype_physdev *physdev = get_freetype_dev( dev );
6935 realization_info_t *info = ptr;
6939 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6940 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6943 FIXME("(%p, %p): stub!\n", physdev->font, info);
6946 if(FT_IS_SCALABLE(physdev->font->ft_face))
6949 info->cache_num = physdev->font->cache_num;
6950 info->unknown2 = -1;
6954 /*************************************************************************
6955 * Kerning support for TrueType fonts
6957 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6959 struct TT_kern_table
6965 struct TT_kern_subtable
6974 USHORT horizontal : 1;
6976 USHORT cross_stream: 1;
6977 USHORT override : 1;
6978 USHORT reserved1 : 4;
6984 struct TT_format0_kern_subtable
6988 USHORT entrySelector;
6999 static DWORD parse_format0_kern_subtable(GdiFont *font,
7000 const struct TT_format0_kern_subtable *tt_f0_ks,
7001 const USHORT *glyph_to_char,
7002 KERNINGPAIR *kern_pair, DWORD cPairs)
7005 const struct TT_kern_pair *tt_kern_pair;
7007 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7009 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7011 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7012 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7013 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7015 if (!kern_pair || !cPairs)
7018 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7020 nPairs = min(nPairs, cPairs);
7022 for (i = 0; i < nPairs; i++)
7024 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7025 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7026 /* this algorithm appears to better match what Windows does */
7027 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7028 if (kern_pair->iKernAmount < 0)
7030 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7031 kern_pair->iKernAmount -= font->ppem;
7033 else if (kern_pair->iKernAmount > 0)
7035 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7036 kern_pair->iKernAmount += font->ppem;
7038 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7040 TRACE("left %u right %u value %d\n",
7041 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7045 TRACE("copied %u entries\n", nPairs);
7049 /*************************************************************
7050 * freetype_GetKerningPairs
7052 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7056 const struct TT_kern_table *tt_kern_table;
7057 const struct TT_kern_subtable *tt_kern_subtable;
7059 USHORT *glyph_to_char;
7061 struct freetype_physdev *physdev = get_freetype_dev( dev );
7063 if (!(font = physdev->font))
7065 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7066 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7070 EnterCriticalSection( &freetype_cs );
7071 if (font->total_kern_pairs != (DWORD)-1)
7073 if (cPairs && kern_pair)
7075 cPairs = min(cPairs, font->total_kern_pairs);
7076 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7078 else cPairs = font->total_kern_pairs;
7080 LeaveCriticalSection( &freetype_cs );
7084 font->total_kern_pairs = 0;
7086 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7088 if (length == GDI_ERROR)
7090 TRACE("no kerning data in the font\n");
7091 LeaveCriticalSection( &freetype_cs );
7095 buf = HeapAlloc(GetProcessHeap(), 0, length);
7098 WARN("Out of memory\n");
7099 LeaveCriticalSection( &freetype_cs );
7103 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7105 /* build a glyph index to char code map */
7106 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7109 WARN("Out of memory allocating a glyph index to char code map\n");
7110 HeapFree(GetProcessHeap(), 0, buf);
7111 LeaveCriticalSection( &freetype_cs );
7115 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7121 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7123 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7124 font->ft_face->num_glyphs, glyph_code, char_code);
7128 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7130 /* FIXME: This doesn't match what Windows does: it does some fancy
7131 * things with duplicate glyph index to char code mappings, while
7132 * we just avoid overriding existing entries.
7134 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7135 glyph_to_char[glyph_code] = (USHORT)char_code;
7137 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7144 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7145 for (n = 0; n <= 65535; n++)
7146 glyph_to_char[n] = (USHORT)n;
7149 tt_kern_table = buf;
7150 nTables = GET_BE_WORD(tt_kern_table->nTables);
7151 TRACE("version %u, nTables %u\n",
7152 GET_BE_WORD(tt_kern_table->version), nTables);
7154 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7156 for (i = 0; i < nTables; i++)
7158 struct TT_kern_subtable tt_kern_subtable_copy;
7160 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7161 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7162 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7164 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7165 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7166 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7168 /* According to the TrueType specification this is the only format
7169 * that will be properly interpreted by Windows and OS/2
7171 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7173 DWORD new_chunk, old_total = font->total_kern_pairs;
7175 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7176 glyph_to_char, NULL, 0);
7177 font->total_kern_pairs += new_chunk;
7179 if (!font->kern_pairs)
7180 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7181 font->total_kern_pairs * sizeof(*font->kern_pairs));
7183 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7184 font->total_kern_pairs * sizeof(*font->kern_pairs));
7186 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7187 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7190 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7192 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7195 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7196 HeapFree(GetProcessHeap(), 0, buf);
7198 if (cPairs && kern_pair)
7200 cPairs = min(cPairs, font->total_kern_pairs);
7201 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7203 else cPairs = font->total_kern_pairs;
7205 LeaveCriticalSection( &freetype_cs );
7209 static const struct gdi_dc_funcs freetype_funcs =
7211 NULL, /* pAbortDoc */
7212 NULL, /* pAbortPath */
7213 NULL, /* pAlphaBlend */
7214 NULL, /* pAngleArc */
7217 NULL, /* pBeginPath */
7218 NULL, /* pBlendImage */
7219 NULL, /* pChoosePixelFormat */
7221 NULL, /* pCloseFigure */
7222 NULL, /* pCopyBitmap */
7223 NULL, /* pCreateBitmap */
7224 NULL, /* pCreateCompatibleDC */
7225 freetype_CreateDC, /* pCreateDC */
7226 NULL, /* pDeleteBitmap */
7227 freetype_DeleteDC, /* pDeleteDC */
7228 NULL, /* pDeleteObject */
7229 NULL, /* pDescribePixelFormat */
7230 NULL, /* pDeviceCapabilities */
7231 NULL, /* pEllipse */
7233 NULL, /* pEndPage */
7234 NULL, /* pEndPath */
7235 freetype_EnumFonts, /* pEnumFonts */
7236 NULL, /* pEnumICMProfiles */
7237 NULL, /* pExcludeClipRect */
7238 NULL, /* pExtDeviceMode */
7239 NULL, /* pExtEscape */
7240 NULL, /* pExtFloodFill */
7241 NULL, /* pExtSelectClipRgn */
7242 NULL, /* pExtTextOut */
7243 NULL, /* pFillPath */
7244 NULL, /* pFillRgn */
7245 NULL, /* pFlattenPath */
7246 freetype_FontIsLinked, /* pFontIsLinked */
7247 NULL, /* pFrameRgn */
7248 NULL, /* pGdiComment */
7249 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7250 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7251 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7252 freetype_GetCharWidth, /* pGetCharWidth */
7253 NULL, /* pGetDeviceCaps */
7254 NULL, /* pGetDeviceGammaRamp */
7255 freetype_GetFontData, /* pGetFontData */
7256 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7257 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7258 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7259 NULL, /* pGetICMProfile */
7260 NULL, /* pGetImage */
7261 freetype_GetKerningPairs, /* pGetKerningPairs */
7262 NULL, /* pGetNearestColor */
7263 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7264 NULL, /* pGetPixel */
7265 NULL, /* pGetPixelFormat */
7266 NULL, /* pGetSystemPaletteEntries */
7267 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7268 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7269 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7270 freetype_GetTextFace, /* pGetTextFace */
7271 freetype_GetTextMetrics, /* pGetTextMetrics */
7272 NULL, /* pGradientFill */
7273 NULL, /* pIntersectClipRect */
7274 NULL, /* pInvertRgn */
7276 NULL, /* pModifyWorldTransform */
7278 NULL, /* pOffsetClipRgn */
7279 NULL, /* pOffsetViewportOrg */
7280 NULL, /* pOffsetWindowOrg */
7281 NULL, /* pPaintRgn */
7284 NULL, /* pPolyBezier */
7285 NULL, /* pPolyBezierTo */
7286 NULL, /* pPolyDraw */
7287 NULL, /* pPolyPolygon */
7288 NULL, /* pPolyPolyline */
7289 NULL, /* pPolygon */
7290 NULL, /* pPolyline */
7291 NULL, /* pPolylineTo */
7292 NULL, /* pPutImage */
7293 NULL, /* pRealizeDefaultPalette */
7294 NULL, /* pRealizePalette */
7295 NULL, /* pRectangle */
7296 NULL, /* pResetDC */
7297 NULL, /* pRestoreDC */
7298 NULL, /* pRoundRect */
7300 NULL, /* pScaleViewportExt */
7301 NULL, /* pScaleWindowExt */
7302 NULL, /* pSelectBitmap */
7303 NULL, /* pSelectBrush */
7304 NULL, /* pSelectClipPath */
7305 freetype_SelectFont, /* pSelectFont */
7306 NULL, /* pSelectPalette */
7307 NULL, /* pSelectPen */
7308 NULL, /* pSetArcDirection */
7309 NULL, /* pSetBkColor */
7310 NULL, /* pSetBkMode */
7311 NULL, /* pSetDCBrushColor */
7312 NULL, /* pSetDCPenColor */
7313 NULL, /* pSetDIBColorTable */
7314 NULL, /* pSetDIBitsToDevice */
7315 NULL, /* pSetDeviceClipping */
7316 NULL, /* pSetDeviceGammaRamp */
7317 NULL, /* pSetLayout */
7318 NULL, /* pSetMapMode */
7319 NULL, /* pSetMapperFlags */
7320 NULL, /* pSetPixel */
7321 NULL, /* pSetPixelFormat */
7322 NULL, /* pSetPolyFillMode */
7323 NULL, /* pSetROP2 */
7324 NULL, /* pSetRelAbs */
7325 NULL, /* pSetStretchBltMode */
7326 NULL, /* pSetTextAlign */
7327 NULL, /* pSetTextCharacterExtra */
7328 NULL, /* pSetTextColor */
7329 NULL, /* pSetTextJustification */
7330 NULL, /* pSetViewportExt */
7331 NULL, /* pSetViewportOrg */
7332 NULL, /* pSetWindowExt */
7333 NULL, /* pSetWindowOrg */
7334 NULL, /* pSetWorldTransform */
7335 NULL, /* pStartDoc */
7336 NULL, /* pStartPage */
7337 NULL, /* pStretchBlt */
7338 NULL, /* pStretchDIBits */
7339 NULL, /* pStrokeAndFillPath */
7340 NULL, /* pStrokePath */
7341 NULL, /* pSwapBuffers */
7342 NULL, /* pUnrealizePalette */
7343 NULL, /* pWidenPath */
7344 /* OpenGL not supported */
7347 #else /* HAVE_FREETYPE */
7349 /*************************************************************************/
7351 BOOL WineEngInit(void)
7355 BOOL WineEngDestroyFontInstance(HFONT hfont)
7360 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7362 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7366 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7368 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7372 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7374 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7378 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7383 /*************************************************************************
7384 * GetRasterizerCaps (GDI32.@)
7386 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7388 lprs->nSize = sizeof(RASTERIZER_STATUS);
7390 lprs->nLanguageID = 0;
7394 #endif /* HAVE_FREETYPE */