2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
98 #ifdef HAVE_FT2BUILD_H
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
144 static FT_Library library = 0;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix);
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetString);
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
241 FT_Short internal_leading;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
255 NEWTEXTMETRICEXW ntm;
259 typedef struct tagFace {
265 DWORD font_data_size;
269 FT_Fixed font_version;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
279 typedef struct tagFamily {
281 const WCHAR *FamilyName;
282 const WCHAR *EnglishName;
284 struct list *replacement;
289 INT adv; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST {
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping *mapping;
353 const WCHAR *font_name;
358 struct enum_charset_element {
361 WCHAR name[LF_FACESIZE];
364 struct enum_charset_list {
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 struct freetype_physdev
384 struct gdi_physdev dev;
388 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
390 return (struct freetype_physdev *)dev;
393 static const struct gdi_dc_funcs freetype_funcs;
395 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR * const SystemFontValues[] = {
422 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
428 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
438 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
439 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR *default_serif_list[] =
450 bitstream_vera_serif,
454 static const WCHAR *default_fixed_list[] =
458 bitstream_vera_sans_mono,
462 static const WCHAR *default_sans_list[] =
475 typedef struct tagFontSubst {
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
487 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
488 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
489 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
491 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
511 static struct list mappings_list = LIST_INIT( mappings_list );
513 static CRITICAL_SECTION freetype_cs;
514 static CRITICAL_SECTION_DEBUG critsect_debug =
517 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
518 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback = FALSE;
527 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
528 static BOOL get_outline_text_metrics(GdiFont *font);
529 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
531 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
547 * FIXEDFON.FON FixedSys
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
589 GSUB_ScriptRecord ScriptRecord[1];
595 } GSUB_LangSysRecord;
600 GSUB_LangSysRecord LangSysRecord[1];
604 WORD LookupOrder; /* Reserved */
605 WORD ReqFeatureIndex;
607 WORD FeatureIndex[1];
613 } GSUB_FeatureRecord;
617 GSUB_FeatureRecord FeatureRecord[1];
621 WORD FeatureParams; /* Reserved */
623 WORD LookupListIndex[1];
642 } GSUB_CoverageFormat1;
647 WORD StartCoverageIndex;
653 GSUB_RangeRecord RangeRecord[1];
654 } GSUB_CoverageFormat2;
657 WORD SubstFormat; /* = 1 */
660 } GSUB_SingleSubstFormat1;
663 WORD SubstFormat; /* = 2 */
667 }GSUB_SingleSubstFormat2;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
674 static char cached_path[MAX_PATH];
675 static const char *wine = "/Wine", *fonts = "/Fonts";
677 if(*cached_path) return cached_path;
679 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
682 WARN("can't create cached data folder\n");
685 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
688 WARN("can't create cached data path\n");
692 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
694 ERR("Could not create full path\n");
698 strcat(cached_path, wine);
700 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
702 WARN("Couldn't mkdir %s\n", cached_path);
706 strcat(cached_path, fonts);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
716 /******************************************************************
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path)
734 const char *filename;
738 unsigned int size, max_size;
741 TRACE("path %s\n", path);
743 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
746 WARN("failed to get ref\n");
750 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref = FSOpenResFile(&ref, fsRdPerm);
757 TRACE("unable to open resource fork\n");
764 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
767 CloseResFile(res_ref);
771 out_dir = find_cache_dir();
773 filename = strrchr(path, '/');
774 if(!filename) filename = path;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
785 unsigned short *num_faces_ptr, num_faces, face;
788 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
790 fond = Get1IndResource(fond_res, idx);
792 TRACE("got fond resource %d\n", idx);
795 fam_rec = *(FamRec**)fond;
796 num_faces_ptr = (unsigned short *)(fam_rec + 1);
797 num_faces = GET_BE_WORD(*num_faces_ptr);
799 assoc = (AsscEntry*)(num_faces_ptr + 1);
800 TRACE("num faces %04x\n", num_faces);
801 for(face = 0; face < num_faces; face++, assoc++)
804 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
805 unsigned short size, font_id;
808 size = GET_BE_WORD(assoc->fontSize);
809 font_id = GET_BE_WORD(assoc->fontID);
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
816 TRACE("trying to load sfnt id %04x\n", font_id);
817 sfnt = GetResource(sfnt_res, font_id);
820 TRACE("can't get sfnt resource %04x\n", font_id);
824 output = HeapAlloc(GetProcessHeap(), 0, output_len);
829 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
831 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
832 if(fd != -1 || errno == EEXIST)
836 unsigned char *sfnt_data;
839 sfnt_data = *(unsigned char**)sfnt;
840 write(fd, sfnt_data, GetHandleSize(sfnt));
844 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
847 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
849 ret.array[ret.size++] = output;
853 WARN("unable to create %s\n", output);
854 HeapFree(GetProcessHeap(), 0, output);
857 ReleaseResource(sfnt);
860 ReleaseResource(fond);
863 CloseResFile(res_ref);
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed FT_FixedFromFloat(double f)
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
889 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
893 static const struct list *get_face_list_from_family(const Family *family)
895 if (!list_empty(&family->faces))
896 return &family->faces;
898 return family->replacement;
901 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
906 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
907 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
909 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
912 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
914 const struct list *face_list;
915 if(face_name && strcmpiW(face_name, family->FamilyName))
917 face_list = get_face_list_from_family(family);
918 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
922 file = strrchr(face->file, '/');
927 if(!strcasecmp(file, file_nameA))
929 HeapFree(GetProcessHeap(), 0, file_nameA);
934 HeapFree(GetProcessHeap(), 0, file_nameA);
938 static Family *find_family_from_name(const WCHAR *name)
942 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
944 if(!strcmpiW(family->FamilyName, name))
951 static Family *find_family_from_any_name(const WCHAR *name)
955 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
957 if(!strcmpiW(family->FamilyName, name))
959 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
966 static void DumpSubstList(void)
970 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
972 if(psub->from.charset != -1 || psub->to.charset != -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
974 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
976 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
977 debugstr_w(psub->to.name));
982 static LPWSTR strdupW(LPCWSTR p)
985 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
986 ret = HeapAlloc(GetProcessHeap(), 0, len);
991 static LPSTR strdupA(LPCSTR p)
994 DWORD len = (strlen(p) + 1);
995 ret = HeapAlloc(GetProcessHeap(), 0, len);
1000 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1005 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1007 if(!strcmpiW(element->from.name, from_name) &&
1008 (element->from.charset == from_charset ||
1009 element->from.charset == -1))
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1020 FontSubst *from_exist, *to_exist;
1022 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1024 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1026 list_remove(&from_exist->entry);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1028 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1029 HeapFree(GetProcessHeap(), 0, from_exist);
1035 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1039 HeapFree(GetProcessHeap(), 0, subst->to.name);
1040 subst->to.name = strdupW(to_exist->to.name);
1043 list_add_tail(subst_list, &subst->entry);
1048 HeapFree(GetProcessHeap(), 0, subst->from.name);
1049 HeapFree(GetProcessHeap(), 0, subst->to.name);
1050 HeapFree(GetProcessHeap(), 0, subst);
1054 static WCHAR *towstr(UINT cp, const char *str)
1059 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1060 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1061 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1065 static void split_subst_info(NameCs *nc, LPSTR str)
1067 CHAR *p = strrchr(str, ',');
1071 nc->charset = strtol(p+1, NULL, 10);
1074 nc->name = towstr(CP_ACP, str);
1077 static void LoadSubstList(void)
1081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey) == ERROR_SUCCESS) {
1089 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1090 &valuelen, &datalen, NULL, NULL);
1092 valuelen++; /* returned value doesn't include room for '\0' */
1093 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1094 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1098 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1099 &dlen) == ERROR_SUCCESS) {
1100 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1102 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1103 split_subst_info(&psub->from, value);
1104 split_subst_info(&psub->to, data);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1109 psub->to.charset == DEFAULT_CHARSET) {
1110 HeapFree(GetProcessHeap(), 0, psub->to.name);
1111 HeapFree(GetProcessHeap(), 0, psub->from.name);
1112 HeapFree(GetProcessHeap(), 0, psub);
1114 add_font_subst(&font_subst_list, psub, 0);
1116 /* reset dlen and vlen */
1120 HeapFree(GetProcessHeap(), 0, data);
1121 HeapFree(GetProcessHeap(), 0, value);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1138 FT_UInt num_names, name_index;
1140 if(FT_IS_SFNT(ft_face))
1142 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1144 for(name_index = 0; name_index < num_names; name_index++)
1146 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1148 if((name.platform_id == req->platform_id) &&
1149 (name.encoding_id == req->encoding_id) &&
1150 (name.language_id == req->language_id) &&
1151 (name.name_id == req->name_id))
1153 req->string = name.string;
1154 req->string_len = name.string_len;
1161 req->string_len = 0;
1165 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1170 name.platform_id = TT_PLATFORM_MICROSOFT;
1171 name.encoding_id = TT_MS_ID_UNICODE_CS;
1172 name.language_id = language_id;
1173 name.name_id = name_id;
1175 if(get_name_table_entry(ft_face, &name))
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1181 for(i = 0; i < name.string_len / 2; i++)
1183 WORD *tmp = (WORD *)&name.string[i * 2];
1184 ret[i] = GET_BE_WORD(*tmp);
1187 TRACE("Got localised name %s\n", debugstr_w(ret));
1193 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1196 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1197 if(r != ERROR_SUCCESS) return r;
1198 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1199 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1202 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1204 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1207 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1210 DWORD num_strikes, max_strike_key_len;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1218 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1219 face->cached_enum_data = NULL;
1221 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1222 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1224 face->StyleName = strdupW(face_name);
1225 face->family = family;
1226 face->vertical = (family->FamilyName[0] == '@');
1228 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1230 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1231 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1232 face->FullName = fullName;
1235 face->FullName = NULL;
1237 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1238 reg_load_dword(hkey_face, face_italic_value, &italic);
1239 reg_load_dword(hkey_face, face_bold_value, &bold);
1240 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1241 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1243 needed = sizeof(face->fs);
1244 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1246 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1248 face->scalable = TRUE;
1249 memset(&face->size, 0, sizeof(face->size));
1253 face->scalable = FALSE;
1254 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1255 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1256 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1257 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1258 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face->size.height, face->size.width, face->size.size >> 6,
1262 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1266 if (italic) face->ntmFlags |= NTM_ITALIC;
1267 if (bold) face->ntmFlags |= NTM_BOLD;
1268 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face->fs.fsCsb[0], face->fs.fsCsb[1],
1272 face->fs.fsUsb[0], face->fs.fsUsb[1],
1273 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1275 if(!italic && !bold)
1276 list_add_head(&family->faces, &face->entry);
1278 list_add_tail(&family->faces, &face->entry);
1280 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1285 NULL, NULL, NULL, NULL);
1286 if(num_strikes != 0)
1288 WCHAR strike_name[10];
1289 DWORD strike_index = 0;
1291 needed = sizeof(strike_name) / sizeof(WCHAR);
1292 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1293 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1296 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1297 load_face(hkey_strike, face_name, family);
1298 RegCloseKey(hkey_strike);
1299 needed = sizeof(strike_name) / sizeof(WCHAR);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache)
1306 DWORD max_family_key_len, size;
1308 DWORD family_index = 0;
1312 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1313 NULL, NULL, NULL, NULL);
1314 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1316 size = max_family_key_len + 1;
1317 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1318 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1320 WCHAR *english_family = NULL;
1321 DWORD face_index = 0;
1323 DWORD max_face_key_len;
1325 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1326 TRACE("opened family key %s\n", debugstr_w(family_name));
1327 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1329 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1330 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1333 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1334 family->FamilyName = strdupW(family_name);
1335 family->EnglishName = english_family;
1336 list_init(&family->faces);
1337 family->replacement = &family->faces;
1338 list_add_tail(&font_list, &family->entry);
1342 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1343 subst->from.name = strdupW(english_family);
1344 subst->from.charset = -1;
1345 subst->to.name = strdupW(family_name);
1346 subst->to.charset = -1;
1347 add_font_subst(&font_subst_list, subst, 0);
1350 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1351 NULL, NULL, NULL, NULL);
1353 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1354 size = max_face_key_len + 1;
1355 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1356 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1360 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1361 load_face(hkey_face, face_name, family);
1362 RegCloseKey(hkey_face);
1363 size = max_face_key_len + 1;
1365 HeapFree(GetProcessHeap(), 0, face_name);
1366 RegCloseKey(hkey_family);
1367 size = max_family_key_len + 1;
1370 HeapFree(GetProcessHeap(), 0, family_name);
1373 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1376 HKEY hkey_wine_fonts;
1378 /* We don't want to create the fonts key as volatile, so open this first */
1379 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1380 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1381 if(ret != ERROR_SUCCESS)
1383 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1387 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1388 KEY_ALL_ACCESS, NULL, hkey, disposition);
1389 RegCloseKey(hkey_wine_fonts);
1393 static void add_face_to_cache(Face *face)
1395 HKEY hkey_font_cache, hkey_family, hkey_face;
1396 WCHAR *face_key_name;
1398 create_font_cache_key(&hkey_font_cache, NULL);
1400 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1401 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1402 if(face->family->EnglishName)
1403 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1404 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1407 face_key_name = face->StyleName;
1410 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1411 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1412 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1414 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1417 HeapFree(GetProcessHeap(), 0, face_key_name);
1419 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1421 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1422 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1424 reg_save_dword(hkey_face, face_index_value, face->face_index);
1425 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1426 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1427 reg_save_dword(hkey_face, face_version_value, face->font_version);
1428 reg_save_dword(hkey_face, face_external_value, face->external);
1430 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1434 reg_save_dword(hkey_face, face_height_value, face->size.height);
1435 reg_save_dword(hkey_face, face_width_value, face->size.width);
1436 reg_save_dword(hkey_face, face_size_value, face->size.size);
1437 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1438 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1439 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1441 RegCloseKey(hkey_face);
1442 RegCloseKey(hkey_family);
1443 RegCloseKey(hkey_font_cache);
1446 static inline int TestStyles(DWORD flags, DWORD styles)
1448 return (flags & styles) == styles;
1451 static int StyleOrdering(Face *face)
1453 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1455 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1457 if (TestStyles(face->ntmFlags, NTM_BOLD))
1459 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1462 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1463 debugstr_w(face->family->FamilyName),
1464 debugstr_w(face->StyleName),
1470 /* Add a style of face to a font family using an ordering of the list such
1471 that regular fonts come before bold and italic, and single styles come
1472 before compound styles. */
1473 static void AddFaceToFamily(Face *face, Family *family)
1477 LIST_FOR_EACH( entry, &family->faces )
1479 Face *ent = LIST_ENTRY(entry, Face, entry);
1480 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1482 list_add_before( entry, &face->entry );
1485 static WCHAR *prepend_at(WCHAR *family)
1492 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1494 strcpyW(str + 1, family);
1495 HeapFree(GetProcessHeap(), 0, family);
1499 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1501 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1502 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1504 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1510 else if (!strcmpiW( *name, *english ))
1512 HeapFree( GetProcessHeap(), 0, *english );
1518 *name = prepend_at( *name );
1519 *english = prepend_at( *english );
1523 /****************************************************************
1524 * NB This function stores the ptrs to the strings to save copying.
1525 * Don't free them after calling.
1527 static Family *create_family( WCHAR *name, WCHAR *english_name )
1529 Family *family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1530 family->FamilyName = name;
1531 family->EnglishName = english_name;
1532 list_init( &family->faces );
1533 family->replacement = &family->faces;
1538 static Family *get_family( FT_Face ft_face, BOOL vertical )
1541 WCHAR *name, *english_name;
1543 get_family_names( ft_face, &name, &english_name, vertical );
1545 family = find_family_from_name( name );
1549 family = create_family( name, english_name );
1550 list_add_tail( &font_list, &family->entry );
1554 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1555 subst->from.name = strdupW( english_name );
1556 subst->from.charset = -1;
1557 subst->to.name = strdupW( name );
1558 subst->to.charset = -1;
1559 add_font_subst( &font_subst_list, subst, 0 );
1564 HeapFree( GetProcessHeap(), 0, name );
1565 HeapFree( GetProcessHeap(), 0, english_name );
1571 static inline FT_Fixed get_font_version( FT_Face ft_face )
1573 FT_Fixed version = 0;
1576 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1577 if (header) version = header->Font_Revision;
1582 static inline DWORD get_ntm_flags( FT_Face ft_face )
1585 FT_ULong table_size = 0;
1587 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1588 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1589 if (flags == 0) flags = NTM_REGULAR;
1591 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1592 flags |= NTM_PS_OPENTYPE;
1597 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1599 int internal_leading = 0;
1600 FT_WinFNT_HeaderRec winfnt_header;
1602 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1603 internal_leading = winfnt_header.internal_leading;
1605 return internal_leading;
1608 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1613 FT_WinFNT_HeaderRec winfnt_header;
1616 memset( fs, 0, sizeof(*fs) );
1618 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1621 fs->fsUsb[0] = os2->ulUnicodeRange1;
1622 fs->fsUsb[1] = os2->ulUnicodeRange2;
1623 fs->fsUsb[2] = os2->ulUnicodeRange3;
1624 fs->fsUsb[3] = os2->ulUnicodeRange4;
1626 if (os2->version == 0)
1628 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1629 fs->fsCsb[0] = FS_LATIN1;
1631 fs->fsCsb[0] = FS_SYMBOL;
1635 fs->fsCsb[0] = os2->ulCodePageRange1;
1636 fs->fsCsb[1] = os2->ulCodePageRange2;
1641 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1643 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1644 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1645 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1650 if (fs->fsCsb[0] == 0)
1652 /* let's see if we can find any interesting cmaps */
1653 for (i = 0; i < ft_face->num_charmaps; i++)
1655 switch (ft_face->charmaps[i]->encoding)
1657 case FT_ENCODING_UNICODE:
1658 case FT_ENCODING_APPLE_ROMAN:
1659 fs->fsCsb[0] |= FS_LATIN1;
1661 case FT_ENCODING_MS_SYMBOL:
1662 fs->fsCsb[0] |= FS_SYMBOL;
1671 static inline void free_face( Face *face )
1673 HeapFree( GetProcessHeap(), 0, face->file );
1674 HeapFree( GetProcessHeap(), 0, face->StyleName );
1675 HeapFree( GetProcessHeap(), 0, face->FullName );
1676 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1677 HeapFree( GetProcessHeap(), 0, face );
1680 #define ADDFONT_EXTERNAL_FONT 0x01
1681 #define ADDFONT_FORCE_BITMAP 0x02
1682 #define ADDFONT_ADD_TO_CACHE 0x04
1684 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)
1692 struct list *face_elem_ptr;
1694 My_FT_Bitmap_Size *size = NULL;
1697 if(!FT_IS_SCALABLE(ft_face))
1698 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1700 family = get_family( ft_face, vertical );
1702 StyleW = towstr(CP_ACP, ft_face->style_name);
1704 get_fontsig( ft_face, &fs );
1706 version = get_font_version( ft_face );
1707 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1708 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1709 if(!strcmpiW(face->StyleName, StyleW) &&
1710 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1711 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1712 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1713 face->font_version, version);
1714 if(version <= face->font_version) {
1715 TRACE("Original font is newer so skipping this one\n");
1716 HeapFree(GetProcessHeap(), 0, StyleW);
1719 TRACE("Replacing original with this one\n");
1720 list_remove(&face->entry);
1726 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1727 face->cached_enum_data = NULL;
1728 face->StyleName = StyleW;
1729 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1732 face->file = strdupA(file);
1733 face->font_data_ptr = NULL;
1734 face->font_data_size = 0;
1739 face->font_data_ptr = font_data_ptr;
1740 face->font_data_size = font_data_size;
1742 face->face_index = face_index;
1743 face->ntmFlags = get_ntm_flags( ft_face );
1744 face->font_version = version;
1745 face->family = family;
1746 face->vertical = vertical;
1747 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1750 if(FT_IS_SCALABLE(ft_face)) {
1751 memset(&face->size, 0, sizeof(face->size));
1752 face->scalable = TRUE;
1754 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1755 size->height, size->width, size->size >> 6,
1756 size->x_ppem >> 6, size->y_ppem >> 6);
1757 face->size.height = size->height;
1758 face->size.width = size->width;
1759 face->size.size = size->size;
1760 face->size.x_ppem = size->x_ppem;
1761 face->size.y_ppem = size->y_ppem;
1762 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1763 face->scalable = FALSE;
1766 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1767 face->fs.fsCsb[0], face->fs.fsCsb[1],
1768 face->fs.fsUsb[0], face->fs.fsUsb[1],
1769 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1771 if(flags & ADDFONT_ADD_TO_CACHE)
1772 add_face_to_cache(face);
1774 AddFaceToFamily(face, family);
1776 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1778 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1779 debugstr_w(StyleW));
1782 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1787 FT_Long face_index = 0, num_faces;
1790 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1791 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1793 #ifdef HAVE_CARBON_CARBON_H
1796 char **mac_list = expand_mac_font(file);
1799 BOOL had_one = FALSE;
1801 for(cursor = mac_list; *cursor; cursor++)
1804 AddFontToList(*cursor, NULL, 0, flags);
1805 HeapFree(GetProcessHeap(), 0, *cursor);
1807 HeapFree(GetProcessHeap(), 0, mac_list);
1812 #endif /* HAVE_CARBON_CARBON_H */
1817 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1818 err = pFT_New_Face(library, file, face_index, &ft_face);
1821 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1822 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1826 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1830 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*/
1831 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1832 pFT_Done_Face(ft_face);
1836 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1837 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1838 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1839 pFT_Done_Face(ft_face);
1843 if(FT_IS_SFNT(ft_face))
1845 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1846 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1847 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))
1849 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1850 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1851 pFT_Done_Face(ft_face);
1855 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1856 we don't want to load these. */
1857 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1861 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1863 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1864 pFT_Done_Face(ft_face);
1870 if(!ft_face->family_name || !ft_face->style_name) {
1871 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1872 pFT_Done_Face(ft_face);
1876 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1878 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1879 pFT_Done_Face(ft_face);
1883 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1886 if (FT_HAS_VERTICAL(ft_face))
1888 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1892 num_faces = ft_face->num_faces;
1893 pFT_Done_Face(ft_face);
1894 } while(num_faces > ++face_index);
1898 static void DumpFontList(void)
1902 struct list *family_elem_ptr, *face_elem_ptr;
1904 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1905 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1906 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1907 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1908 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1909 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1911 TRACE(" %d", face->size.height);
1918 /***********************************************************
1919 * The replacement list is a way to map an entire font
1920 * family onto another family. For example adding
1922 * [HKCU\Software\Wine\Fonts\Replacements]
1923 * "Wingdings"="Winedings"
1925 * would enumerate the Winedings font both as Winedings and
1926 * Wingdings. However if a real Wingdings font is present the
1927 * replacement does not take place.
1930 static void LoadReplaceList(void)
1933 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1938 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1939 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1941 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1942 &valuelen, &datalen, NULL, NULL);
1944 valuelen++; /* returned value doesn't include room for '\0' */
1945 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1946 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1950 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1951 &dlen) == ERROR_SUCCESS) {
1952 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1953 /* "NewName"="Oldname" */
1954 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1956 if(!find_family_from_any_name(value))
1958 Family * const family = find_family_from_any_name(data);
1961 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1962 if (new_family != NULL)
1964 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1965 new_family->FamilyName = strdupW(value);
1966 new_family->EnglishName = NULL;
1967 list_init(&new_family->faces);
1968 new_family->replacement = &family->faces;
1969 list_add_tail(&font_list, &new_family->entry);
1974 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1979 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1981 /* reset dlen and vlen */
1985 HeapFree(GetProcessHeap(), 0, data);
1986 HeapFree(GetProcessHeap(), 0, value);
1991 static const WCHAR *font_links_list[] =
1993 Lucida_Sans_Unicode,
1994 Microsoft_Sans_Serif,
1998 static const struct font_links_defaults_list
2000 /* Keyed off substitution for "MS Shell Dlg" */
2001 const WCHAR *shelldlg;
2002 /* Maximum of four substitutes, plus terminating NULL pointer */
2003 const WCHAR *substitutes[5];
2004 } font_links_defaults_list[] =
2006 /* Non East-Asian */
2007 { Tahoma, /* FIXME unverified ordering */
2008 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2010 /* Below lists are courtesy of
2011 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2015 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2017 /* Chinese Simplified */
2019 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2023 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2025 /* Chinese Traditional */
2027 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2032 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2034 SYSTEM_LINKS *font_link;
2036 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2038 if(!strcmpiW(font_link->font_name, name))
2045 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2057 SYSTEM_LINKS *font_link;
2059 psub = get_font_subst(&font_subst_list, name, -1);
2060 /* Don't store fonts that are only substitutes for other fonts */
2063 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2067 font_link = find_font_link(name);
2068 if (font_link == NULL)
2070 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2071 font_link->font_name = strdupW(name);
2072 list_init(&font_link->links);
2073 list_add_tail(&system_links, &font_link->entry);
2076 memset(&font_link->fs, 0, sizeof font_link->fs);
2077 for (i = 0; values[i] != NULL; i++)
2079 const struct list *face_list;
2080 CHILD_FONT *child_font;
2083 if (!strcmpiW(name,value))
2085 psub = get_font_subst(&font_subst_list, value, -1);
2087 value = psub->to.name;
2088 family = find_family_from_name(value);
2092 /* Use first extant filename for this Family */
2093 face_list = get_face_list_from_family(family);
2094 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2098 file = strrchr(face->file, '/');
2107 fileW = towstr(CP_UNIXCP, file);
2109 face = find_face_from_filename(fileW, value);
2112 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2116 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2117 child_font->face = face;
2118 child_font->font = NULL;
2119 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2120 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2121 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2122 list_add_tail(&font_link->links, &child_font->entry);
2124 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2125 HeapFree(GetProcessHeap(), 0, fileW);
2131 /*************************************************************
2134 static BOOL init_system_links(void)
2138 DWORD type, max_val, max_data, val_len, data_len, index;
2139 WCHAR *value, *data;
2140 WCHAR *entry, *next;
2141 SYSTEM_LINKS *font_link, *system_font_link;
2142 CHILD_FONT *child_font;
2143 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2144 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2145 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2150 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2152 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2153 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2154 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2155 val_len = max_val + 1;
2156 data_len = max_data;
2158 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2160 psub = get_font_subst(&font_subst_list, value, -1);
2161 /* Don't store fonts that are only substitutes for other fonts */
2164 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2167 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2168 font_link->font_name = strdupW(value);
2169 memset(&font_link->fs, 0, sizeof font_link->fs);
2170 list_init(&font_link->links);
2171 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2174 CHILD_FONT *child_font;
2176 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2178 next = entry + strlenW(entry) + 1;
2180 face_name = strchrW(entry, ',');
2184 while(isspaceW(*face_name))
2187 psub = get_font_subst(&font_subst_list, face_name, -1);
2189 face_name = psub->to.name;
2191 face = find_face_from_filename(entry, face_name);
2194 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2198 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2199 child_font->face = face;
2200 child_font->font = NULL;
2201 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2202 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2203 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2204 list_add_tail(&font_link->links, &child_font->entry);
2206 list_add_tail(&system_links, &font_link->entry);
2208 val_len = max_val + 1;
2209 data_len = max_data;
2212 HeapFree(GetProcessHeap(), 0, value);
2213 HeapFree(GetProcessHeap(), 0, data);
2218 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2220 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2224 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2226 const FontSubst *psub2;
2227 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2229 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2231 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2232 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2234 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2235 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2237 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2239 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2245 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2248 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2249 system_font_link->font_name = strdupW(System);
2250 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2251 list_init(&system_font_link->links);
2253 face = find_face_from_filename(tahoma_ttf, Tahoma);
2256 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2257 child_font->face = face;
2258 child_font->font = NULL;
2259 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2260 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2261 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2262 list_add_tail(&system_font_link->links, &child_font->entry);
2264 font_link = find_font_link(Tahoma);
2265 if (font_link != NULL)
2267 CHILD_FONT *font_link_entry;
2268 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2270 CHILD_FONT *new_child;
2271 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2272 new_child->face = font_link_entry->face;
2273 new_child->font = NULL;
2274 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2275 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2276 list_add_tail(&system_font_link->links, &new_child->entry);
2279 list_add_tail(&system_links, &system_font_link->entry);
2283 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2286 struct dirent *dent;
2287 char path[MAX_PATH];
2289 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2291 dir = opendir(dirname);
2293 WARN("Can't open directory %s\n", debugstr_a(dirname));
2296 while((dent = readdir(dir)) != NULL) {
2297 struct stat statbuf;
2299 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2302 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2304 sprintf(path, "%s/%s", dirname, dent->d_name);
2306 if(stat(path, &statbuf) == -1)
2308 WARN("Can't stat %s\n", debugstr_a(path));
2311 if(S_ISDIR(statbuf.st_mode))
2312 ReadFontDir(path, external_fonts);
2315 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2316 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2317 AddFontToList(path, NULL, 0, addfont_flags);
2324 static void load_fontconfig_fonts(void)
2326 #ifdef SONAME_LIBFONTCONFIG
2327 void *fc_handle = NULL;
2336 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2338 TRACE("Wine cannot find the fontconfig library (%s).\n",
2339 SONAME_LIBFONTCONFIG);
2342 #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;}
2343 LOAD_FUNCPTR(FcConfigGetCurrent);
2344 LOAD_FUNCPTR(FcFontList);
2345 LOAD_FUNCPTR(FcFontSetDestroy);
2346 LOAD_FUNCPTR(FcInit);
2347 LOAD_FUNCPTR(FcObjectSetAdd);
2348 LOAD_FUNCPTR(FcObjectSetCreate);
2349 LOAD_FUNCPTR(FcObjectSetDestroy);
2350 LOAD_FUNCPTR(FcPatternCreate);
2351 LOAD_FUNCPTR(FcPatternDestroy);
2352 LOAD_FUNCPTR(FcPatternGetBool);
2353 LOAD_FUNCPTR(FcPatternGetString);
2356 if(!pFcInit()) return;
2358 config = pFcConfigGetCurrent();
2359 pat = pFcPatternCreate();
2360 os = pFcObjectSetCreate();
2361 pFcObjectSetAdd(os, FC_FILE);
2362 pFcObjectSetAdd(os, FC_SCALABLE);
2363 fontset = pFcFontList(config, pat, os);
2364 if(!fontset) return;
2365 for(i = 0; i < fontset->nfont; i++) {
2368 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2370 TRACE("fontconfig: %s\n", file);
2372 /* We're just interested in OT/TT fonts for now, so this hack just
2373 picks up the scalable fonts without extensions .pf[ab] to save time
2374 loading every other font */
2376 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2378 TRACE("not scalable\n");
2382 len = strlen( file );
2383 if(len < 4) continue;
2384 ext = &file[ len - 3 ];
2385 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2386 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2388 pFcFontSetDestroy(fontset);
2389 pFcObjectSetDestroy(os);
2390 pFcPatternDestroy(pat);
2396 static BOOL load_font_from_data_dir(LPCWSTR file)
2399 const char *data_dir = wine_get_data_dir();
2401 if (!data_dir) data_dir = wine_get_build_dir();
2408 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2410 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2412 strcpy(unix_name, data_dir);
2413 strcat(unix_name, "/fonts/");
2415 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2417 EnterCriticalSection( &freetype_cs );
2418 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2419 LeaveCriticalSection( &freetype_cs );
2420 HeapFree(GetProcessHeap(), 0, unix_name);
2425 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2427 static const WCHAR slashW[] = {'\\','\0'};
2429 WCHAR windowsdir[MAX_PATH];
2432 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2433 strcatW(windowsdir, fontsW);
2434 strcatW(windowsdir, slashW);
2435 strcatW(windowsdir, file);
2436 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2437 EnterCriticalSection( &freetype_cs );
2438 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2439 LeaveCriticalSection( &freetype_cs );
2440 HeapFree(GetProcessHeap(), 0, unixname);
2445 static void load_system_fonts(void)
2448 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2449 const WCHAR * const *value;
2451 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2454 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2455 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2456 strcatW(windowsdir, fontsW);
2457 for(value = SystemFontValues; *value; value++) {
2458 dlen = sizeof(data);
2459 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2463 sprintfW(pathW, fmtW, windowsdir, data);
2464 if((unixname = wine_get_unix_file_name(pathW))) {
2465 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2466 HeapFree(GetProcessHeap(), 0, unixname);
2469 load_font_from_data_dir(data);
2476 /*************************************************************
2478 * This adds registry entries for any externally loaded fonts
2479 * (fonts from fontconfig or FontDirs). It also deletes entries
2480 * of no longer existing fonts.
2483 static void update_reg_entries(void)
2485 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2490 struct list *family_elem_ptr, *face_elem_ptr;
2492 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2493 static const WCHAR spaceW[] = {' ', '\0'};
2496 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2497 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2498 ERR("Can't create Windows font reg key\n");
2502 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2503 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2504 ERR("Can't create Windows font reg key\n");
2508 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2509 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2510 ERR("Can't create external font reg key\n");
2514 /* enumerate the fonts and add external ones to the two keys */
2516 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2517 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2518 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2519 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2520 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2521 if(!face->external) continue;
2523 if (!(face->ntmFlags & NTM_REGULAR))
2524 len = len_fam + strlenW(face->StyleName) + 1;
2525 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2526 strcpyW(valueW, family->FamilyName);
2527 if(len != len_fam) {
2528 strcatW(valueW, spaceW);
2529 strcatW(valueW, face->StyleName);
2531 strcatW(valueW, TrueType);
2533 file = wine_get_dos_file_name(face->file);
2535 len = strlenW(file) + 1;
2538 if((path = strrchr(face->file, '/')) == NULL)
2542 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2544 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2545 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2547 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2548 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2549 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2551 HeapFree(GetProcessHeap(), 0, file);
2552 HeapFree(GetProcessHeap(), 0, valueW);
2556 if(external_key) RegCloseKey(external_key);
2557 if(win9x_key) RegCloseKey(win9x_key);
2558 if(winnt_key) RegCloseKey(winnt_key);
2562 static void delete_external_font_keys(void)
2564 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2565 DWORD dlen, vlen, datalen, valuelen, i, type;
2569 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2570 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2571 ERR("Can't create Windows font reg key\n");
2575 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2576 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2577 ERR("Can't create Windows font reg key\n");
2581 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2582 ERR("Can't create external font reg key\n");
2586 /* Delete all external fonts added last time */
2588 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2589 &valuelen, &datalen, NULL, NULL);
2590 valuelen++; /* returned value doesn't include room for '\0' */
2591 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2592 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2594 dlen = datalen * sizeof(WCHAR);
2597 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2598 &dlen) == ERROR_SUCCESS) {
2600 RegDeleteValueW(winnt_key, valueW);
2601 RegDeleteValueW(win9x_key, valueW);
2602 /* reset dlen and vlen */
2606 HeapFree(GetProcessHeap(), 0, data);
2607 HeapFree(GetProcessHeap(), 0, valueW);
2609 /* Delete the old external fonts key */
2610 RegCloseKey(external_key);
2611 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2614 if(win9x_key) RegCloseKey(win9x_key);
2615 if(winnt_key) RegCloseKey(winnt_key);
2618 /*************************************************************
2619 * WineEngAddFontResourceEx
2622 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2628 if (ft_handle) /* do it only if we have freetype up and running */
2633 FIXME("Ignoring flags %x\n", flags);
2635 if((unixname = wine_get_unix_file_name(file)))
2637 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2639 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2640 EnterCriticalSection( &freetype_cs );
2641 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2642 LeaveCriticalSection( &freetype_cs );
2643 HeapFree(GetProcessHeap(), 0, unixname);
2645 if (!ret && !strchrW(file, '\\')) {
2646 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2647 ret = load_font_from_winfonts_dir(file);
2649 /* Try in datadir/fonts (or builddir/fonts),
2650 * needed for Magic the Gathering Online
2652 ret = load_font_from_data_dir(file);
2659 /*************************************************************
2660 * WineEngAddFontMemResourceEx
2663 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2667 if (ft_handle) /* do it only if we have freetype up and running */
2669 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2671 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2672 memcpy(pFontCopy, pbFont, cbFont);
2674 EnterCriticalSection( &freetype_cs );
2675 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2676 LeaveCriticalSection( &freetype_cs );
2680 TRACE("AddFontToList failed\n");
2681 HeapFree(GetProcessHeap(), 0, pFontCopy);
2684 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2685 * For now return something unique but quite random
2687 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2688 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2695 /*************************************************************
2696 * WineEngRemoveFontResourceEx
2699 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2702 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2706 static const struct nls_update_font_list
2708 UINT ansi_cp, oem_cp;
2709 const char *oem, *fixed, *system;
2710 const char *courier, *serif, *small, *sserif;
2711 /* these are for font substitutes */
2712 const char *shelldlg, *tmsrmn;
2713 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2717 const char *from, *to;
2718 } arial_0, courier_new_0, times_new_roman_0;
2719 } nls_update_font_list[] =
2721 /* Latin 1 (United States) */
2722 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2723 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2724 "Tahoma","Times New Roman",
2725 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2728 /* Latin 1 (Multilingual) */
2729 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2730 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2731 "Tahoma","Times New Roman", /* FIXME unverified */
2732 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2735 /* Eastern Europe */
2736 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2737 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2738 "Tahoma","Times New Roman", /* FIXME unverified */
2739 "Fixedsys,238", "System,238",
2740 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2741 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2742 { "Arial CE,0", "Arial,238" },
2743 { "Courier New CE,0", "Courier New,238" },
2744 { "Times New Roman CE,0", "Times New Roman,238" }
2747 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2748 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2749 "Tahoma","Times New Roman", /* FIXME unverified */
2750 "Fixedsys,204", "System,204",
2751 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2752 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2753 { "Arial Cyr,0", "Arial,204" },
2754 { "Courier New Cyr,0", "Courier New,204" },
2755 { "Times New Roman Cyr,0", "Times New Roman,204" }
2758 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2759 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2760 "Tahoma","Times New Roman", /* FIXME unverified */
2761 "Fixedsys,161", "System,161",
2762 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2763 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2764 { "Arial Greek,0", "Arial,161" },
2765 { "Courier New Greek,0", "Courier New,161" },
2766 { "Times New Roman Greek,0", "Times New Roman,161" }
2769 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2770 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2771 "Tahoma","Times New Roman", /* FIXME unverified */
2772 "Fixedsys,162", "System,162",
2773 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2774 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2775 { "Arial Tur,0", "Arial,162" },
2776 { "Courier New Tur,0", "Courier New,162" },
2777 { "Times New Roman Tur,0", "Times New Roman,162" }
2780 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2781 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2782 "Tahoma","Times New Roman", /* FIXME unverified */
2783 "Fixedsys,177", "System,177",
2784 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2785 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2789 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2790 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2791 "Tahoma","Times New Roman", /* FIXME unverified */
2792 "Fixedsys,178", "System,178",
2793 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2794 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2798 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2799 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2800 "Tahoma","Times New Roman", /* FIXME unverified */
2801 "Fixedsys,186", "System,186",
2802 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2803 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2804 { "Arial Baltic,0", "Arial,186" },
2805 { "Courier New Baltic,0", "Courier New,186" },
2806 { "Times New Roman Baltic,0", "Times New Roman,186" }
2809 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2810 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2811 "Tahoma","Times New Roman", /* FIXME unverified */
2812 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2816 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2817 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2818 "Tahoma","Times New Roman", /* FIXME unverified */
2819 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2823 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2824 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2825 "MS UI Gothic","MS Serif",
2826 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2829 /* Chinese Simplified */
2830 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2831 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2832 "SimSun", "NSimSun",
2833 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2837 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2838 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2840 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2843 /* Chinese Traditional */
2844 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2845 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2846 "PMingLiU", "MingLiU",
2847 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2852 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2854 return ( ansi_cp == 932 /* CP932 for Japanese */
2855 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2856 || ansi_cp == 949 /* CP949 for Korean */
2857 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2860 static inline HKEY create_fonts_NT_registry_key(void)
2864 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2865 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2869 static inline HKEY create_fonts_9x_registry_key(void)
2873 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2874 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2878 static inline HKEY create_config_fonts_registry_key(void)
2882 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2883 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2887 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2889 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2890 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2891 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2892 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2895 static void set_value_key(HKEY hkey, const char *name, const char *value)
2898 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2900 RegDeleteValueA(hkey, name);
2903 static void update_font_info(void)
2905 char buf[40], cpbuf[40];
2908 UINT i, ansi_cp = 0, oem_cp = 0;
2911 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2914 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2915 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2916 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2917 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2918 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2920 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2921 if (is_dbcs_ansi_cp(ansi_cp))
2922 use_default_fallback = TRUE;
2925 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2927 if (!strcmp( buf, cpbuf )) /* already set correctly */
2932 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2934 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2936 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2939 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2943 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2944 nls_update_font_list[i].oem_cp == oem_cp)
2946 hkey = create_config_fonts_registry_key();
2947 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2948 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2949 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2952 hkey = create_fonts_NT_registry_key();
2953 add_font_list(hkey, &nls_update_font_list[i]);
2956 hkey = create_fonts_9x_registry_key();
2957 add_font_list(hkey, &nls_update_font_list[i]);
2960 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2962 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2963 strlen(nls_update_font_list[i].shelldlg)+1);
2964 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2965 strlen(nls_update_font_list[i].tmsrmn)+1);
2967 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2968 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2969 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2970 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2971 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2972 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2973 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2974 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2976 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2977 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2978 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2986 /* Delete the FontSubstitutes from other locales */
2987 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2989 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2990 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2991 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2997 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3000 static BOOL init_freetype(void)
3002 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3005 "Wine cannot find the FreeType font library. To enable Wine to\n"
3006 "use TrueType fonts please install a version of FreeType greater than\n"
3007 "or equal to 2.0.5.\n"
3008 "http://www.freetype.org\n");
3012 #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;}
3014 LOAD_FUNCPTR(FT_Done_Face)
3015 LOAD_FUNCPTR(FT_Get_Char_Index)
3016 LOAD_FUNCPTR(FT_Get_First_Char)
3017 LOAD_FUNCPTR(FT_Get_Module)
3018 LOAD_FUNCPTR(FT_Get_Next_Char)
3019 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3020 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3021 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3022 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3023 LOAD_FUNCPTR(FT_Init_FreeType)
3024 LOAD_FUNCPTR(FT_Library_Version)
3025 LOAD_FUNCPTR(FT_Load_Glyph)
3026 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3027 LOAD_FUNCPTR(FT_Matrix_Multiply)
3028 #ifndef FT_MULFIX_INLINED
3029 LOAD_FUNCPTR(FT_MulFix)
3031 LOAD_FUNCPTR(FT_New_Face)
3032 LOAD_FUNCPTR(FT_New_Memory_Face)
3033 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3034 LOAD_FUNCPTR(FT_Outline_Transform)
3035 LOAD_FUNCPTR(FT_Outline_Translate)
3036 LOAD_FUNCPTR(FT_Render_Glyph)
3037 LOAD_FUNCPTR(FT_Select_Charmap)
3038 LOAD_FUNCPTR(FT_Set_Charmap)
3039 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3040 LOAD_FUNCPTR(FT_Vector_Transform)
3041 LOAD_FUNCPTR(FT_Vector_Unit)
3043 /* Don't warn if these ones are missing */
3044 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3045 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3046 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3049 if(pFT_Init_FreeType(&library) != 0) {
3050 ERR("Can't init FreeType library\n");
3051 wine_dlclose(ft_handle, NULL, 0);
3055 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3057 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3058 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3059 ((FT_Version.minor << 8) & 0x00ff00) |
3060 ((FT_Version.patch ) & 0x0000ff);
3062 font_driver = &freetype_funcs;
3067 "Wine cannot find certain functions that it needs inside the FreeType\n"
3068 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3069 "FreeType to at least version 2.1.4.\n"
3070 "http://www.freetype.org\n");
3071 wine_dlclose(ft_handle, NULL, 0);
3076 static void init_font_list(void)
3078 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3079 static const WCHAR pathW[] = {'P','a','t','h',0};
3081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3082 WCHAR windowsdir[MAX_PATH];
3085 const char *data_dir;
3087 delete_external_font_keys();
3089 /* load the system bitmap fonts */
3090 load_system_fonts();
3092 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3093 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3094 strcatW(windowsdir, fontsW);
3095 if((unixname = wine_get_unix_file_name(windowsdir)))
3097 ReadFontDir(unixname, FALSE);
3098 HeapFree(GetProcessHeap(), 0, unixname);
3101 /* load the system truetype fonts */
3102 data_dir = wine_get_data_dir();
3103 if (!data_dir) data_dir = wine_get_build_dir();
3104 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3106 strcpy(unixname, data_dir);
3107 strcat(unixname, "/fonts/");
3108 ReadFontDir(unixname, TRUE);
3109 HeapFree(GetProcessHeap(), 0, unixname);
3112 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3113 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3114 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3116 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3117 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3118 &hkey) == ERROR_SUCCESS)
3120 LPWSTR data, valueW;
3121 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3122 &valuelen, &datalen, NULL, NULL);
3124 valuelen++; /* returned value doesn't include room for '\0' */
3125 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3126 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3129 dlen = datalen * sizeof(WCHAR);
3131 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3132 &dlen) == ERROR_SUCCESS)
3134 if(data[0] && (data[1] == ':'))
3136 if((unixname = wine_get_unix_file_name(data)))
3138 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3139 HeapFree(GetProcessHeap(), 0, unixname);
3142 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3144 WCHAR pathW[MAX_PATH];
3145 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3148 sprintfW(pathW, fmtW, windowsdir, data);
3149 if((unixname = wine_get_unix_file_name(pathW)))
3151 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3152 HeapFree(GetProcessHeap(), 0, unixname);
3155 load_font_from_data_dir(data);
3157 /* reset dlen and vlen */
3162 HeapFree(GetProcessHeap(), 0, data);
3163 HeapFree(GetProcessHeap(), 0, valueW);
3167 load_fontconfig_fonts();
3169 /* then look in any directories that we've specified in the config file */
3170 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3171 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3177 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3179 len += sizeof(WCHAR);
3180 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3181 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3183 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3184 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3185 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3186 TRACE( "got font path %s\n", debugstr_a(valueA) );
3190 LPSTR next = strchr( ptr, ':' );
3191 if (next) *next++ = 0;
3192 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3193 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3195 strcpy( unixname, home );
3196 strcat( unixname, ptr + 1 );
3197 ReadFontDir( unixname, TRUE );
3198 HeapFree( GetProcessHeap(), 0, unixname );
3201 ReadFontDir( ptr, TRUE );
3204 HeapFree( GetProcessHeap(), 0, valueA );
3206 HeapFree( GetProcessHeap(), 0, valueW );
3212 /* Mac default font locations. */
3213 ReadFontDir( "/Library/Fonts", TRUE );
3214 ReadFontDir( "/Network/Library/Fonts", TRUE );
3215 ReadFontDir( "/System/Library/Fonts", TRUE );
3216 if ((home = getenv( "HOME" )))
3218 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3219 strcpy( unixname, home );
3220 strcat( unixname, "/Library/Fonts" );
3221 ReadFontDir( unixname, TRUE);
3222 HeapFree( GetProcessHeap(), 0, unixname );
3227 static BOOL move_to_front(const WCHAR *name)
3229 Family *family, *cursor2;
3230 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3232 if(!strcmpiW(family->FamilyName, name))
3234 list_remove(&family->entry);
3235 list_add_head(&font_list, &family->entry);
3242 static BOOL set_default(const WCHAR **name_list)
3246 if (move_to_front(*name_list)) return TRUE;
3253 static void reorder_font_list(void)
3255 set_default( default_serif_list );
3256 set_default( default_fixed_list );
3257 set_default( default_sans_list );
3260 /*************************************************************
3263 * Initialize FreeType library and create a list of available faces
3265 BOOL WineEngInit(void)
3267 HKEY hkey_font_cache;
3271 /* update locale dependent font info in registry */
3274 if(!init_freetype()) return FALSE;
3276 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3278 ERR("Failed to create font mutex\n");
3281 WaitForSingleObject(font_mutex, INFINITE);
3283 create_font_cache_key(&hkey_font_cache, &disposition);
3285 if(disposition == REG_CREATED_NEW_KEY)
3288 load_font_list_from_cache(hkey_font_cache);
3290 RegCloseKey(hkey_font_cache);
3292 reorder_font_list();
3299 if(disposition == REG_CREATED_NEW_KEY)
3300 update_reg_entries();
3302 init_system_links();
3304 ReleaseMutex(font_mutex);
3309 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3312 TT_HoriHeader *pHori;
3316 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3317 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3319 if(height == 0) height = 16;
3321 /* Calc. height of EM square:
3323 * For +ve lfHeight we have
3324 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3325 * Re-arranging gives:
3326 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3328 * For -ve lfHeight we have
3330 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3331 * with il = winAscent + winDescent - units_per_em]
3336 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3337 ppem = MulDiv(ft_face->units_per_EM, height,
3338 pHori->Ascender - pHori->Descender);
3340 ppem = MulDiv(ft_face->units_per_EM, height,
3341 pOS2->usWinAscent + pOS2->usWinDescent);
3349 static struct font_mapping *map_font_file( const char *name )
3351 struct font_mapping *mapping;
3355 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3356 if (fstat( fd, &st ) == -1) goto error;
3358 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3360 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3362 mapping->refcount++;
3367 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3370 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3373 if (mapping->data == MAP_FAILED)
3375 HeapFree( GetProcessHeap(), 0, mapping );
3378 mapping->refcount = 1;
3379 mapping->dev = st.st_dev;
3380 mapping->ino = st.st_ino;
3381 mapping->size = st.st_size;
3382 list_add_tail( &mappings_list, &mapping->entry );
3390 static void unmap_font_file( struct font_mapping *mapping )
3392 if (!--mapping->refcount)
3394 list_remove( &mapping->entry );
3395 munmap( mapping->data, mapping->size );
3396 HeapFree( GetProcessHeap(), 0, mapping );
3400 static LONG load_VDMX(GdiFont*, LONG);
3402 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3409 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3413 if (!(font->mapping = map_font_file( face->file )))
3415 WARN("failed to map %s\n", debugstr_a(face->file));
3418 data_ptr = font->mapping->data;
3419 data_size = font->mapping->size;
3423 data_ptr = face->font_data_ptr;
3424 data_size = face->font_data_size;
3427 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3429 ERR("FT_New_Face rets %d\n", err);
3433 /* set it here, as load_VDMX needs it */
3434 font->ft_face = ft_face;
3436 if(FT_IS_SCALABLE(ft_face)) {
3437 /* load the VDMX table if we have one */
3438 font->ppem = load_VDMX(font, height);
3440 font->ppem = calc_ppem_for_height(ft_face, height);
3441 TRACE("height %d => ppem %d\n", height, font->ppem);
3443 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3444 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3446 font->ppem = height;
3447 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3448 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3454 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3456 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3457 a single face with the requested charset. The idea is to check if
3458 the selected font supports the current ANSI codepage, if it does
3459 return the corresponding charset, else return the first charset */
3462 int acp = GetACP(), i;
3466 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3468 const SYSTEM_LINKS *font_link;
3470 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3471 return csi.ciCharset;
3473 font_link = find_font_link(family_name);
3474 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3475 return csi.ciCharset;
3478 for(i = 0; i < 32; i++) {
3480 if(face->fs.fsCsb[0] & fs0) {
3481 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3483 return csi.ciCharset;
3486 FIXME("TCI failing on %x\n", fs0);
3490 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3491 face->fs.fsCsb[0], face->file);
3493 return DEFAULT_CHARSET;
3496 static GdiFont *alloc_font(void)
3498 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3500 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3501 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3503 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3504 ret->total_kern_pairs = (DWORD)-1;
3505 ret->kern_pairs = NULL;
3506 list_init(&ret->hfontlist);
3507 list_init(&ret->child_fonts);
3511 static void free_font(GdiFont *font)
3513 struct list *cursor, *cursor2;
3516 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3518 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3519 list_remove(cursor);
3521 free_font(child->font);
3522 HeapFree(GetProcessHeap(), 0, child);
3525 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3527 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3528 DeleteObject(hfontlist->hfont);
3529 list_remove(&hfontlist->entry);
3530 HeapFree(GetProcessHeap(), 0, hfontlist);
3533 if (font->ft_face) pFT_Done_Face(font->ft_face);
3534 if (font->mapping) unmap_font_file( font->mapping );
3535 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3536 HeapFree(GetProcessHeap(), 0, font->potm);
3537 HeapFree(GetProcessHeap(), 0, font->name);
3538 for (i = 0; i < font->gmsize; i++)
3539 HeapFree(GetProcessHeap(),0,font->gm[i]);
3540 HeapFree(GetProcessHeap(), 0, font->gm);
3541 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3542 HeapFree(GetProcessHeap(), 0, font);
3546 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3548 FT_Face ft_face = font->ft_face;
3552 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3559 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3561 /* make sure value of len is the value freetype says it needs */
3564 FT_ULong needed = 0;
3565 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3566 if( !err && needed < len) len = needed;
3568 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3571 TRACE("Can't find table %c%c%c%c\n",
3572 /* bytes were reversed */
3573 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3574 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3580 /*************************************************************
3583 * load the vdmx entry for the specified height
3586 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3587 ( ( (FT_ULong)_x4 << 24 ) | \
3588 ( (FT_ULong)_x3 << 16 ) | \
3589 ( (FT_ULong)_x2 << 8 ) | \
3592 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3607 static LONG load_VDMX(GdiFont *font, LONG height)
3611 BYTE devXRatio, devYRatio;
3612 USHORT numRecs, numRatios;
3613 DWORD result, offset = -1;
3617 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3619 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3622 /* FIXME: need the real device aspect ratio */
3626 numRecs = GET_BE_WORD(hdr[1]);
3627 numRatios = GET_BE_WORD(hdr[2]);
3629 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3630 for(i = 0; i < numRatios; i++) {
3633 offset = (3 * 2) + (i * sizeof(Ratios));
3634 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3637 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3639 if((ratio.xRatio == 0 &&
3640 ratio.yStartRatio == 0 &&
3641 ratio.yEndRatio == 0) ||
3642 (devXRatio == ratio.xRatio &&
3643 devYRatio >= ratio.yStartRatio &&
3644 devYRatio <= ratio.yEndRatio))
3646 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3647 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3648 offset = GET_BE_WORD(tmp);
3654 FIXME("No suitable ratio found\n");
3658 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3660 BYTE startsz, endsz;
3663 recs = GET_BE_WORD(group.recs);
3664 startsz = group.startsz;
3665 endsz = group.endsz;
3667 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3669 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3670 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3671 if(result == GDI_ERROR) {
3672 FIXME("Failed to retrieve vTable\n");
3677 for(i = 0; i < recs; i++) {
3678 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3679 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3680 ppem = GET_BE_WORD(vTable[i * 3]);
3682 if(yMax + -yMin == height) {
3685 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3688 if(yMax + -yMin > height) {
3691 goto end; /* failed */
3693 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3694 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3695 ppem = GET_BE_WORD(vTable[i * 3]);
3696 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3702 TRACE("ppem not found for height %d\n", height);
3706 HeapFree(GetProcessHeap(), 0, vTable);
3712 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3714 if(font->font_desc.hash != fd->hash) return TRUE;
3715 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3716 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3717 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3718 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3721 static void calc_hash(FONT_DESC *pfd)
3723 DWORD hash = 0, *ptr, two_chars;
3727 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3729 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3731 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3733 pwc = (WCHAR *)&two_chars;
3735 *pwc = toupperW(*pwc);
3737 *pwc = toupperW(*pwc);
3741 hash ^= !pfd->can_use_bitmap;
3746 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3751 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3755 fd.can_use_bitmap = can_use_bitmap;
3758 /* try the child list */
3759 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3760 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3761 if(!fontcmp(ret, &fd)) {
3762 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3763 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3764 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3765 if(hflist->hfont == hfont)
3771 /* try the in-use list */
3772 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3773 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3774 if(!fontcmp(ret, &fd)) {
3775 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3776 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3777 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3778 if(hflist->hfont == hfont)
3781 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3782 hflist->hfont = hfont;
3783 list_add_head(&ret->hfontlist, &hflist->entry);
3788 /* then the unused list */
3789 font_elem_ptr = list_head(&unused_gdi_font_list);
3790 while(font_elem_ptr) {
3791 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3792 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3793 if(!fontcmp(ret, &fd)) {
3794 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3795 assert(list_empty(&ret->hfontlist));
3796 TRACE("Found %p in unused list\n", ret);
3797 list_remove(&ret->entry);
3798 list_add_head(&gdi_font_list, &ret->entry);
3799 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3800 hflist->hfont = hfont;
3801 list_add_head(&ret->hfontlist, &hflist->entry);
3808 static void add_to_cache(GdiFont *font)
3810 static DWORD cache_num = 1;
3812 font->cache_num = cache_num++;
3813 list_add_head(&gdi_font_list, &font->entry);
3816 /*************************************************************
3817 * create_child_font_list
3819 static BOOL create_child_font_list(GdiFont *font)
3822 SYSTEM_LINKS *font_link;
3823 CHILD_FONT *font_link_entry, *new_child;
3827 psub = get_font_subst(&font_subst_list, font->name, -1);
3828 font_name = psub ? psub->to.name : font->name;
3829 font_link = find_font_link(font_name);
3830 if (font_link != NULL)
3832 TRACE("found entry in system list\n");
3833 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3835 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3836 new_child->face = font_link_entry->face;
3837 new_child->font = NULL;
3838 list_add_tail(&font->child_fonts, &new_child->entry);
3839 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3844 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3845 * Sans Serif. This is how asian windows get default fallbacks for fonts
3847 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3848 font->charset != OEM_CHARSET &&
3849 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3851 font_link = find_font_link(szDefaultFallbackLink);
3852 if (font_link != NULL)
3854 TRACE("found entry in default fallback list\n");
3855 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3857 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3858 new_child->face = font_link_entry->face;
3859 new_child->font = NULL;
3860 list_add_tail(&font->child_fonts, &new_child->entry);
3861 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3870 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3872 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3874 if (pFT_Set_Charmap)
3877 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3879 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3881 for (i = 0; i < ft_face->num_charmaps; i++)
3883 if (ft_face->charmaps[i]->encoding == encoding)
3885 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3886 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3888 switch (ft_face->charmaps[i]->platform_id)
3891 cmap_def = ft_face->charmaps[i];
3893 case 0: /* Apple Unicode */
3894 cmap0 = ft_face->charmaps[i];
3896 case 1: /* Macintosh */
3897 cmap1 = ft_face->charmaps[i];
3900 cmap2 = ft_face->charmaps[i];
3902 case 3: /* Microsoft */
3903 cmap3 = ft_face->charmaps[i];
3908 if (cmap3) /* prefer Microsoft cmap table */
3909 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3911 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3913 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3915 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3917 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3919 return ft_err == FT_Err_Ok;
3922 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3926 /*************************************************************
3929 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3930 LPCWSTR output, const DEVMODEW *devmode )
3932 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3934 if (!physdev) return FALSE;
3935 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3940 /*************************************************************
3943 static BOOL freetype_DeleteDC( PHYSDEV dev )
3945 struct freetype_physdev *physdev = get_freetype_dev( dev );
3946 HeapFree( GetProcessHeap(), 0, physdev );
3951 /*************************************************************
3952 * freetype_SelectFont
3954 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3956 struct freetype_physdev *physdev = get_freetype_dev( dev );
3958 Face *face, *best, *best_bitmap;
3959 Family *family, *last_resort_family;
3960 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
3961 INT height, width = 0;
3962 unsigned int score = 0, new_score;
3963 signed int diff = 0, newdiff;
3964 BOOL bd, it, can_use_bitmap, want_vertical;
3969 FontSubst *psub = NULL;
3970 DC *dc = get_dc_ptr( dev->hdc );
3971 const SYSTEM_LINKS *font_link;
3973 if (!hfont) /* notification that the font has been changed by another driver */
3976 physdev->font = NULL;
3977 release_dc_ptr( dc );
3981 GetObjectW( hfont, sizeof(lf), &lf );
3982 lf.lfWidth = abs(lf.lfWidth);
3984 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3986 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3987 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3988 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3991 if(dc->GraphicsMode == GM_ADVANCED)
3993 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3994 /* Try to avoid not necessary glyph transformations */
3995 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3997 lf.lfHeight *= fabs(dcmat.eM11);
3998 lf.lfWidth *= fabs(dcmat.eM11);
3999 dcmat.eM11 = dcmat.eM22 = 1.0;
4004 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4005 font scaling abilities. */
4006 dcmat.eM11 = dcmat.eM22 = 1.0;
4007 dcmat.eM21 = dcmat.eM12 = 0;
4008 if (dc->vport2WorldValid)
4010 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4011 lf.lfOrientation = -lf.lfOrientation;
4012 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4013 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4017 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4018 dcmat.eM21, dcmat.eM22);
4021 EnterCriticalSection( &freetype_cs );
4023 /* check the cache first */
4024 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4025 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4029 if(list_empty(&font_list)) /* No fonts installed */
4031 TRACE("No fonts installed\n");
4035 TRACE("not in cache\n");
4038 ret->font_desc.matrix = dcmat;
4039 ret->font_desc.lf = lf;
4040 ret->font_desc.can_use_bitmap = can_use_bitmap;
4041 calc_hash(&ret->font_desc);
4042 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4043 hflist->hfont = hfont;
4044 list_add_head(&ret->hfontlist, &hflist->entry);
4046 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4047 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4048 original value lfCharSet. Note this is a special case for
4049 Symbol and doesn't happen at least for "Wingdings*" */
4051 if(!strcmpiW(lf.lfFaceName, SymbolW))
4052 lf.lfCharSet = SYMBOL_CHARSET;
4054 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4055 switch(lf.lfCharSet) {
4056 case DEFAULT_CHARSET:
4057 csi.fs.fsCsb[0] = 0;
4060 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4061 csi.fs.fsCsb[0] = 0;
4067 if(lf.lfFaceName[0] != '\0') {
4068 CHILD_FONT *font_link_entry;
4069 LPWSTR FaceName = lf.lfFaceName;
4071 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4074 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4075 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4076 if (psub->to.charset != -1)
4077 lf.lfCharSet = psub->to.charset;
4080 /* We want a match on name and charset or just name if
4081 charset was DEFAULT_CHARSET. If the latter then
4082 we fixup the returned charset later in get_nearest_charset
4083 where we'll either use the charset of the current ansi codepage
4084 or if that's unavailable the first charset that the font supports.
4086 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4087 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4088 if (!strcmpiW(family->FamilyName, FaceName) ||
4089 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4091 font_link = find_font_link(family->FamilyName);
4092 face_list = get_face_list_from_family(family);
4093 LIST_FOR_EACH(face_elem_ptr, face_list) {
4094 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4095 if (!(face->scalable || can_use_bitmap))
4097 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4099 if (font_link != NULL &&
4100 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4102 if (!csi.fs.fsCsb[0])
4108 /* Search by full face name. */
4109 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4110 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4111 face_list = get_face_list_from_family(family);
4112 LIST_FOR_EACH(face_elem_ptr, face_list) {
4113 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4114 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4115 (face->scalable || can_use_bitmap))
4117 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4119 font_link = find_font_link(family->FamilyName);
4120 if (font_link != NULL &&
4121 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4128 * Try check the SystemLink list first for a replacement font.
4129 * We may find good replacements there.
4131 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4133 if(!strcmpiW(font_link->font_name, FaceName) ||
4134 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4136 TRACE("found entry in system list\n");
4137 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4139 const SYSTEM_LINKS *links;
4141 face = font_link_entry->face;
4142 if (!(face->scalable || can_use_bitmap))
4144 family = face->family;
4145 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4147 links = find_font_link(family->FamilyName);
4148 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4155 psub = NULL; /* substitution is no more relevant */
4157 /* If requested charset was DEFAULT_CHARSET then try using charset
4158 corresponding to the current ansi codepage */
4159 if (!csi.fs.fsCsb[0])
4162 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4163 FIXME("TCI failed on codepage %d\n", acp);
4164 csi.fs.fsCsb[0] = 0;
4166 lf.lfCharSet = csi.ciCharset;
4169 want_vertical = (lf.lfFaceName[0] == '@');
4171 /* Face families are in the top 4 bits of lfPitchAndFamily,
4172 so mask with 0xF0 before testing */
4174 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4175 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4176 strcpyW(lf.lfFaceName, defFixed);
4177 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4178 strcpyW(lf.lfFaceName, defSerif);
4179 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4180 strcpyW(lf.lfFaceName, defSans);
4182 strcpyW(lf.lfFaceName, defSans);
4183 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4184 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4185 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4186 font_link = find_font_link(family->FamilyName);
4187 face_list = get_face_list_from_family(family);
4188 LIST_FOR_EACH(face_elem_ptr, face_list) {
4189 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4190 if (!(face->scalable || can_use_bitmap))
4192 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4194 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4200 last_resort_family = NULL;
4201 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4202 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4203 font_link = find_font_link(family->FamilyName);
4204 face_list = get_face_list_from_family(family);
4205 LIST_FOR_EACH(face_elem_ptr, face_list) {
4206 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4207 if(face->vertical == want_vertical &&
4208 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4209 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4212 if(can_use_bitmap && !last_resort_family)
4213 last_resort_family = family;
4218 if(last_resort_family) {
4219 family = last_resort_family;
4220 csi.fs.fsCsb[0] = 0;
4224 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4225 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4226 face_list = get_face_list_from_family(family);
4227 LIST_FOR_EACH(face_elem_ptr, face_list) {
4228 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4229 if(face->scalable && face->vertical == want_vertical) {
4230 csi.fs.fsCsb[0] = 0;
4231 WARN("just using first face for now\n");
4234 if(can_use_bitmap && !last_resort_family)
4235 last_resort_family = family;
4238 if(!last_resort_family) {
4239 FIXME("can't find a single appropriate font - bailing\n");
4245 WARN("could only find a bitmap font - this will probably look awful!\n");
4246 family = last_resort_family;
4247 csi.fs.fsCsb[0] = 0;
4250 it = lf.lfItalic ? 1 : 0;
4251 bd = lf.lfWeight > 550 ? 1 : 0;
4253 height = lf.lfHeight;
4255 face = best = best_bitmap = NULL;
4256 font_link = find_font_link(family->FamilyName);
4257 face_list = get_face_list_from_family(family);
4258 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4260 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4261 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4266 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4267 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4268 new_score = (italic ^ it) + (bold ^ bd);
4269 if(!best || new_score <= score)
4271 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4272 italic, bold, it, bd);
4275 if(best->scalable && score == 0) break;
4279 newdiff = height - (signed int)(best->size.height);
4281 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4282 if(!best_bitmap || new_score < score ||
4283 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4285 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4288 if(score == 0 && diff == 0) break;
4295 face = best->scalable ? best : best_bitmap;
4296 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4297 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4300 height = lf.lfHeight;
4304 if(csi.fs.fsCsb[0]) {
4305 ret->charset = lf.lfCharSet;
4306 ret->codepage = csi.ciACP;
4309 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4311 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4312 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4314 ret->aveWidth = height ? lf.lfWidth : 0;
4316 if(!face->scalable) {
4317 /* Windows uses integer scaling factors for bitmap fonts */
4318 INT scale, scaled_height;
4319 GdiFont *cachedfont;
4321 /* FIXME: rotation of bitmap fonts is ignored */
4322 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4324 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4325 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4326 dcmat.eM11 = dcmat.eM22 = 1.0;
4327 /* As we changed the matrix, we need to search the cache for the font again,
4328 * otherwise we might explode the cache. */
4329 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4330 TRACE("Found cached font after non-scalable matrix rescale!\n");
4335 calc_hash(&ret->font_desc);
4337 if (height != 0) height = diff;
4338 height += face->size.height;
4340 scale = (height + face->size.height - 1) / face->size.height;
4341 scaled_height = scale * face->size.height;
4342 /* Only jump to the next height if the difference <= 25% original height */
4343 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4344 /* The jump between unscaled and doubled is delayed by 1 */
4345 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4346 ret->scale_y = scale;
4348 width = face->size.x_ppem >> 6;
4349 height = face->size.y_ppem >> 6;
4353 TRACE("font scale y: %f\n", ret->scale_y);
4355 ret->ft_face = OpenFontFace(ret, face, width, height);
4364 ret->ntmFlags = face->ntmFlags;
4366 if (ret->charset == SYMBOL_CHARSET &&
4367 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4370 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4374 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4377 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4378 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4379 ret->underline = lf.lfUnderline ? 0xff : 0;
4380 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4381 create_child_font_list(ret);
4383 if (face->vertical) /* We need to try to load the GSUB table */
4385 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4386 if (length != GDI_ERROR)
4388 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4389 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4390 TRACE("Loaded GSUB table of %i bytes\n",length);
4394 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4401 physdev->font = ret;
4403 LeaveCriticalSection( &freetype_cs );
4404 release_dc_ptr( dc );
4405 return ret ? hfont : 0;
4408 static void dump_gdi_font_list(void)
4411 struct list *elem_ptr;
4413 TRACE("---------- gdiFont Cache ----------\n");
4414 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4415 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4416 TRACE("gdiFont=%p %s %d\n",
4417 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4420 TRACE("---------- Unused gdiFont Cache ----------\n");
4421 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4422 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4423 TRACE("gdiFont=%p %s %d\n",
4424 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4427 TRACE("---------- Child gdiFont Cache ----------\n");
4428 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4429 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4430 TRACE("gdiFont=%p %s %d\n",
4431 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4435 /*************************************************************
4436 * WineEngDestroyFontInstance
4438 * free the gdiFont associated with this handle
4441 BOOL WineEngDestroyFontInstance(HFONT handle)
4446 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4450 EnterCriticalSection( &freetype_cs );
4452 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4454 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4455 while(hfontlist_elem_ptr) {
4456 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4457 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4458 if(hflist->hfont == handle) {
4459 TRACE("removing child font %p from child list\n", gdiFont);
4460 list_remove(&gdiFont->entry);
4461 LeaveCriticalSection( &freetype_cs );
4467 TRACE("destroying hfont=%p\n", handle);
4469 dump_gdi_font_list();
4471 font_elem_ptr = list_head(&gdi_font_list);
4472 while(font_elem_ptr) {
4473 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4474 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4476 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4477 while(hfontlist_elem_ptr) {
4478 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4479 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4480 if(hflist->hfont == handle) {
4481 list_remove(&hflist->entry);
4482 HeapFree(GetProcessHeap(), 0, hflist);
4486 if(list_empty(&gdiFont->hfontlist)) {
4487 TRACE("Moving to Unused list\n");
4488 list_remove(&gdiFont->entry);
4489 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4494 font_elem_ptr = list_head(&unused_gdi_font_list);
4495 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4496 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4497 while(font_elem_ptr) {
4498 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4499 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4500 TRACE("freeing %p\n", gdiFont);
4501 list_remove(&gdiFont->entry);
4504 LeaveCriticalSection( &freetype_cs );
4508 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4515 id += IDS_FIRST_SCRIPT;
4516 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4517 if (!rsrc) return 0;
4518 hMem = LoadResource( gdi32_module, rsrc );
4519 if (!hMem) return 0;
4521 p = LockResource( hMem );
4523 while (id--) p += *p + 1;
4525 i = min(LF_FACESIZE - 1, *p);
4526 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4532 /***************************************************
4533 * create_enum_charset_list
4535 * This function creates charset enumeration list because in DEFAULT_CHARSET
4536 * case, the ANSI codepage's charset takes precedence over other charsets.
4537 * This function works as a filter other than DEFAULT_CHARSET case.
4539 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4544 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4545 csi.fs.fsCsb[0] != 0) {
4546 list->element[n].mask = csi.fs.fsCsb[0];
4547 list->element[n].charset = csi.ciCharset;
4548 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4551 else { /* charset is DEFAULT_CHARSET or invalid. */
4554 /* Set the current codepage's charset as the first element. */
4556 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4557 csi.fs.fsCsb[0] != 0) {
4558 list->element[n].mask = csi.fs.fsCsb[0];
4559 list->element[n].charset = csi.ciCharset;
4560 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4564 /* Fill out left elements. */
4565 for (i = 0; i < 32; i++) {
4567 fs.fsCsb[0] = 1L << i;
4569 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4570 continue; /* skip, already added. */
4571 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4572 continue; /* skip, this is an invalid fsCsb bit. */
4574 list->element[n].mask = fs.fsCsb[0];
4575 list->element[n].charset = csi.ciCharset;
4576 load_script_name( i, list->element[n].name );
4585 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4586 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4591 if (face->cached_enum_data)
4594 *pelf = face->cached_enum_data->elf;
4595 *pntm = face->cached_enum_data->ntm;
4596 *ptype = face->cached_enum_data->type;
4600 font = alloc_font();
4602 if(face->scalable) {
4603 height = -2048; /* 2048 is the most common em size */
4606 height = face->size.y_ppem >> 6;
4607 width = face->size.x_ppem >> 6;
4609 font->scale_y = 1.0;
4611 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4617 font->name = strdupW(face->family->FamilyName);
4618 font->ntmFlags = face->ntmFlags;
4620 if (get_outline_text_metrics(font))
4622 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4624 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4626 lstrcpynW(pelf->elfLogFont.lfFaceName,
4627 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4629 lstrcpynW(pelf->elfFullName,
4630 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4632 lstrcpynW(pelf->elfStyle,
4633 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4638 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4640 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4642 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4644 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4646 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4647 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4650 pntm->ntmTm.ntmFlags = face->ntmFlags;
4651 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4652 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4653 pntm->ntmFontSig = face->fs;
4655 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4657 pelf->elfLogFont.lfEscapement = 0;
4658 pelf->elfLogFont.lfOrientation = 0;
4659 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4660 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4661 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4662 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4663 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4664 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4665 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4666 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4667 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4668 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4669 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4672 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4673 *ptype |= TRUETYPE_FONTTYPE;
4674 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4675 *ptype |= DEVICE_FONTTYPE;
4676 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4677 *ptype |= RASTER_FONTTYPE;
4679 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4680 if (face->cached_enum_data)
4682 face->cached_enum_data->elf = *pelf;
4683 face->cached_enum_data->ntm = *pntm;
4684 face->cached_enum_data->type = *ptype;
4690 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
4692 static const WCHAR spaceW[] = { ' ', 0 };
4694 strcpyW(full_name, family_name);
4695 strcatW(full_name, spaceW);
4696 strcatW(full_name, style_name);
4699 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4701 const struct list *face_list, *face_elem_ptr;
4703 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4705 face_list = get_face_list_from_family(family);
4706 LIST_FOR_EACH(face_elem_ptr, face_list)
4708 WCHAR full_family_name[LF_FULLFACESIZE];
4709 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4711 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4713 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4714 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4718 create_full_name(full_family_name, family->FamilyName, face->StyleName);
4719 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4725 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
4727 WCHAR full_family_name[LF_FULLFACESIZE];
4729 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
4731 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4733 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4734 debugstr_w(family_name), debugstr_w(face->StyleName));
4738 create_full_name(full_family_name, family_name, face->StyleName);
4739 return !strcmpiW(lf->lfFaceName, full_family_name);
4742 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
4743 FONTENUMPROCW proc, LPARAM lparam)
4746 NEWTEXTMETRICEXW ntm;
4750 GetEnumStructs(face, &elf, &ntm, &type);
4751 for(i = 0; i < list->total; i++) {
4752 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4753 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4754 load_script_name( IDS_OEM_DOS, elf.elfScript );
4755 i = list->total; /* break out of loop after enumeration */
4756 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4759 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4760 strcpyW(elf.elfScript, list->element[i].name);
4761 if (!elf.elfScript[0])
4762 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4764 /* Font Replacement */
4765 if (family != face->family)
4767 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
4768 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
4770 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4771 debugstr_w(elf.elfLogFont.lfFaceName),
4772 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4773 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4774 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4775 ntm.ntmTm.ntmFlags);
4776 /* release section before callback (FIXME) */
4777 LeaveCriticalSection( &freetype_cs );
4778 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4779 EnterCriticalSection( &freetype_cs );
4784 /*************************************************************
4785 * freetype_EnumFonts
4787 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4791 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4793 struct enum_charset_list enum_charsets;
4797 lf.lfCharSet = DEFAULT_CHARSET;
4798 lf.lfPitchAndFamily = 0;
4799 lf.lfFaceName[0] = 0;
4803 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4805 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4808 EnterCriticalSection( &freetype_cs );
4809 if(plf->lfFaceName[0]) {
4811 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4814 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4815 debugstr_w(psub->to.name));
4817 strcpyW(lf.lfFaceName, psub->to.name);
4821 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4822 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4823 if(family_matches(family, plf)) {
4824 face_list = get_face_list_from_family(family);
4825 LIST_FOR_EACH(face_elem_ptr, face_list) {
4826 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4827 if (!face_matches(family->FamilyName, face, plf)) continue;
4828 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4833 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4834 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4835 face_list = get_face_list_from_family(family);
4836 face_elem_ptr = list_head(face_list);
4837 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4838 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4841 LeaveCriticalSection( &freetype_cs );
4845 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4847 pt->x.value = vec->x >> 6;
4848 pt->x.fract = (vec->x & 0x3f) << 10;
4849 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4850 pt->y.value = vec->y >> 6;
4851 pt->y.fract = (vec->y & 0x3f) << 10;
4852 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4856 /***************************************************
4857 * According to the MSDN documentation on WideCharToMultiByte,
4858 * certain codepages cannot set the default_used parameter.
4859 * This returns TRUE if the codepage can set that parameter, false else
4860 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4862 static BOOL codepage_sets_default_used(UINT codepage)
4876 * GSUB Table handling functions
4879 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4881 const GSUB_CoverageFormat1* cf1;
4885 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4887 int count = GET_BE_WORD(cf1->GlyphCount);
4889 TRACE("Coverage Format 1, %i glyphs\n",count);
4890 for (i = 0; i < count; i++)
4891 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4895 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4897 const GSUB_CoverageFormat2* cf2;
4900 cf2 = (const GSUB_CoverageFormat2*)cf1;
4902 count = GET_BE_WORD(cf2->RangeCount);
4903 TRACE("Coverage Format 2, %i ranges\n",count);
4904 for (i = 0; i < count; i++)
4906 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4908 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4909 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4911 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4912 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4918 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4923 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4925 const GSUB_ScriptList *script;
4926 const GSUB_Script *deflt = NULL;
4928 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4930 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4931 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4933 const GSUB_Script *scr;
4936 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4937 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4939 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4941 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4947 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4951 const GSUB_LangSys *Lang;
4953 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4955 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4957 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4958 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4960 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4963 offset = GET_BE_WORD(script->DefaultLangSys);
4966 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4972 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4975 const GSUB_FeatureList *feature;
4976 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4978 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4979 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4981 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4982 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4984 const GSUB_Feature *feat;
4985 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4992 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4996 const GSUB_LookupList *lookup;
4997 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4999 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5000 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5002 const GSUB_LookupTable *look;
5003 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5004 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5005 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5006 if (GET_BE_WORD(look->LookupType) != 1)
5007 FIXME("We only handle SubType 1\n");
5012 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5014 const GSUB_SingleSubstFormat1 *ssf1;
5015 offset = GET_BE_WORD(look->SubTable[j]);
5016 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5017 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5019 int offset = GET_BE_WORD(ssf1->Coverage);
5020 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5021 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5023 TRACE(" Glyph 0x%x ->",glyph);
5024 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5025 TRACE(" 0x%x\n",glyph);
5030 const GSUB_SingleSubstFormat2 *ssf2;
5034 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5035 offset = GET_BE_WORD(ssf1->Coverage);
5036 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5037 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5038 TRACE(" Coverage index %i\n",index);
5041 TRACE(" Glyph is 0x%x ->",glyph);
5042 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5043 TRACE("0x%x\n",glyph);
5052 static const char* get_opentype_script(const GdiFont *font)
5055 * I am not sure if this is the correct way to generate our script tag
5058 switch (font->charset)
5060 case ANSI_CHARSET: return "latn";
5061 case BALTIC_CHARSET: return "latn"; /* ?? */
5062 case CHINESEBIG5_CHARSET: return "hani";
5063 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5064 case GB2312_CHARSET: return "hani";
5065 case GREEK_CHARSET: return "grek";
5066 case HANGUL_CHARSET: return "hang";
5067 case RUSSIAN_CHARSET: return "cyrl";
5068 case SHIFTJIS_CHARSET: return "kana";
5069 case TURKISH_CHARSET: return "latn"; /* ?? */
5070 case VIETNAMESE_CHARSET: return "latn";
5071 case JOHAB_CHARSET: return "latn"; /* ?? */
5072 case ARABIC_CHARSET: return "arab";
5073 case HEBREW_CHARSET: return "hebr";
5074 case THAI_CHARSET: return "thai";
5075 default: return "latn";
5079 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5081 const GSUB_Header *header;
5082 const GSUB_Script *script;
5083 const GSUB_LangSys *language;
5084 const GSUB_Feature *feature;
5086 if (!font->GSUB_Table)
5089 header = font->GSUB_Table;
5091 script = GSUB_get_script_table(header, get_opentype_script(font));
5094 TRACE("Script not found\n");
5097 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5100 TRACE("Language not found\n");
5103 feature = GSUB_get_feature(header, language, "vrt2");
5105 feature = GSUB_get_feature(header, language, "vert");
5108 TRACE("vrt2/vert feature not found\n");
5111 return GSUB_apply_feature(header, feature, glyph);
5114 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5118 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5119 WCHAR wc = (WCHAR)glyph;
5121 BOOL *default_used_pointer;
5124 default_used_pointer = NULL;
5125 default_used = FALSE;
5126 if (codepage_sets_default_used(font->codepage))
5127 default_used_pointer = &default_used;
5128 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5131 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5132 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5136 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5138 if (glyph < 0x100) glyph += 0xf000;
5139 /* there is a number of old pre-Unicode "broken" TTFs, which
5140 do have symbols at U+00XX instead of U+f0XX */
5141 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5142 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5144 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5149 /*************************************************************
5150 * freetype_GetGlyphIndices
5152 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5154 struct freetype_physdev *physdev = get_freetype_dev( dev );
5157 BOOL got_default = FALSE;
5161 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5162 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5165 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5167 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5172 EnterCriticalSection( &freetype_cs );
5174 for(i = 0; i < count; i++)
5176 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5181 if (FT_IS_SFNT(physdev->font->ft_face))
5183 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5184 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5189 get_text_metrics(physdev->font, &textm);
5190 default_char = textm.tmDefaultChar;
5194 pgi[i] = default_char;
5197 LeaveCriticalSection( &freetype_cs );
5201 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5203 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5204 return !memcmp(matrix, &identity, sizeof(FMAT2));
5207 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5209 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5210 return !memcmp(matrix, &identity, sizeof(MAT2));
5213 static inline BYTE get_max_level( UINT format )
5217 case GGO_GRAY2_BITMAP: return 4;
5218 case GGO_GRAY4_BITMAP: return 16;
5219 case GGO_GRAY8_BITMAP: return 64;
5224 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5226 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5227 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5230 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5231 FT_Face ft_face = incoming_font->ft_face;
5232 GdiFont *font = incoming_font;
5233 FT_UInt glyph_index;
5234 DWORD width, height, pitch, needed = 0;
5235 FT_Bitmap ft_bitmap;
5237 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5239 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5240 double widthRatio = 1.0;
5241 FT_Matrix transMat = identityMat;
5242 FT_Matrix transMatUnrotated;
5243 BOOL needsTransform = FALSE;
5244 BOOL tategaki = (font->GSUB_Table != NULL);
5245 UINT original_index;
5247 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5248 buflen, buf, lpmat);
5250 TRACE("font transform %f %f %f %f\n",
5251 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5252 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5254 if(format & GGO_GLYPH_INDEX) {
5255 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5256 original_index = glyph;
5257 format &= ~GGO_GLYPH_INDEX;
5259 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5260 ft_face = font->ft_face;
5261 original_index = glyph_index;
5264 if(format & GGO_UNHINTED) {
5265 load_flags |= FT_LOAD_NO_HINTING;
5266 format &= ~GGO_UNHINTED;
5269 /* tategaki never appears to happen to lower glyph index */
5270 if (glyph_index < TATEGAKI_LOWER_BOUND )
5273 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5274 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5275 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5276 font->gmsize * sizeof(GM*));
5278 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5279 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5281 *lpgm = FONT_GM(font,original_index)->gm;
5282 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5283 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5284 lpgm->gmCellIncX, lpgm->gmCellIncY);
5285 return 1; /* FIXME */
5289 if (!font->gm[original_index / GM_BLOCK_SIZE])
5290 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5292 /* Scaling factor */
5297 get_text_metrics(font, &tm);
5299 widthRatio = (double)font->aveWidth;
5300 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5303 widthRatio = font->scale_y;
5305 /* Scaling transform */
5306 if (widthRatio != 1.0 || font->scale_y != 1.0)
5309 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5312 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5314 pFT_Matrix_Multiply(&scaleMat, &transMat);
5315 needsTransform = TRUE;
5318 /* Slant transform */
5319 if (font->fake_italic) {
5322 slantMat.xx = (1 << 16);
5323 slantMat.xy = ((1 << 16) >> 2);
5325 slantMat.yy = (1 << 16);
5326 pFT_Matrix_Multiply(&slantMat, &transMat);
5327 needsTransform = TRUE;
5330 /* Rotation transform */
5331 transMatUnrotated = transMat;
5332 if(font->orientation && !tategaki) {
5333 FT_Matrix rotationMat;
5335 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5336 pFT_Vector_Unit(&vecAngle, angle);
5337 rotationMat.xx = vecAngle.x;
5338 rotationMat.xy = -vecAngle.y;
5339 rotationMat.yx = -rotationMat.xy;
5340 rotationMat.yy = rotationMat.xx;
5342 pFT_Matrix_Multiply(&rotationMat, &transMat);
5343 needsTransform = TRUE;
5346 /* World transform */
5347 if (!is_identity_FMAT2(&font->font_desc.matrix))
5350 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5351 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5352 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5353 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5354 pFT_Matrix_Multiply(&worldMat, &transMat);
5355 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5356 needsTransform = TRUE;
5359 /* Extra transformation specified by caller */
5360 if (!is_identity_MAT2(lpmat))
5363 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5364 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5365 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5366 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5367 pFT_Matrix_Multiply(&extraMat, &transMat);
5368 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5369 needsTransform = TRUE;
5372 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5373 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5374 format == GGO_GRAY8_BITMAP))
5376 load_flags |= FT_LOAD_NO_BITMAP;
5379 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5382 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5386 if(!needsTransform) {
5387 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5388 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5389 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5391 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5392 bottom = (ft_face->glyph->metrics.horiBearingY -
5393 ft_face->glyph->metrics.height) & -64;
5394 lpgm->gmCellIncX = adv;
5395 lpgm->gmCellIncY = 0;
5402 for(xc = 0; xc < 2; xc++) {
5403 for(yc = 0; yc < 2; yc++) {
5404 vec.x = (ft_face->glyph->metrics.horiBearingX +
5405 xc * ft_face->glyph->metrics.width);
5406 vec.y = ft_face->glyph->metrics.horiBearingY -
5407 yc * ft_face->glyph->metrics.height;
5408 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5409 pFT_Vector_Transform(&vec, &transMat);
5410 if(xc == 0 && yc == 0) {
5411 left = right = vec.x;
5412 top = bottom = vec.y;
5414 if(vec.x < left) left = vec.x;
5415 else if(vec.x > right) right = vec.x;
5416 if(vec.y < bottom) bottom = vec.y;
5417 else if(vec.y > top) top = vec.y;
5422 right = (right + 63) & -64;
5423 bottom = bottom & -64;
5424 top = (top + 63) & -64;
5426 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5427 vec.x = ft_face->glyph->metrics.horiAdvance;
5429 pFT_Vector_Transform(&vec, &transMat);
5430 lpgm->gmCellIncX = (vec.x+63) >> 6;
5431 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5433 vec.x = ft_face->glyph->metrics.horiAdvance;
5435 pFT_Vector_Transform(&vec, &transMatUnrotated);
5436 adv = (vec.x+63) >> 6;
5440 bbx = (right - left) >> 6;
5441 lpgm->gmBlackBoxX = (right - left) >> 6;
5442 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5443 lpgm->gmptGlyphOrigin.x = left >> 6;
5444 lpgm->gmptGlyphOrigin.y = top >> 6;
5446 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5447 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5448 lpgm->gmCellIncX, lpgm->gmCellIncY);
5450 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5451 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5453 FONT_GM(font,original_index)->gm = *lpgm;
5454 FONT_GM(font,original_index)->adv = adv;
5455 FONT_GM(font,original_index)->lsb = lsb;
5456 FONT_GM(font,original_index)->bbx = bbx;
5457 FONT_GM(font,original_index)->init = TRUE;
5460 if(format == GGO_METRICS)
5462 return 1; /* FIXME */
5465 if(ft_face->glyph->format != ft_glyph_format_outline &&
5466 (format == GGO_NATIVE || format == GGO_BEZIER))
5468 TRACE("loaded a bitmap\n");
5474 width = lpgm->gmBlackBoxX;
5475 height = lpgm->gmBlackBoxY;
5476 pitch = ((width + 31) >> 5) << 2;
5477 needed = pitch * height;
5479 if(!buf || !buflen) break;
5481 switch(ft_face->glyph->format) {
5482 case ft_glyph_format_bitmap:
5484 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5485 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5486 INT h = ft_face->glyph->bitmap.rows;
5488 memcpy(dst, src, w);
5489 src += ft_face->glyph->bitmap.pitch;
5495 case ft_glyph_format_outline:
5496 ft_bitmap.width = width;
5497 ft_bitmap.rows = height;
5498 ft_bitmap.pitch = pitch;
5499 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5500 ft_bitmap.buffer = buf;
5503 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5505 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5507 /* Note: FreeType will only set 'black' bits for us. */
5508 memset(buf, 0, needed);
5509 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5513 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5518 case GGO_GRAY2_BITMAP:
5519 case GGO_GRAY4_BITMAP:
5520 case GGO_GRAY8_BITMAP:
5521 case WINE_GGO_GRAY16_BITMAP:
5523 unsigned int max_level, row, col;
5526 width = lpgm->gmBlackBoxX;
5527 height = lpgm->gmBlackBoxY;
5528 pitch = (width + 3) / 4 * 4;
5529 needed = pitch * height;
5531 if(!buf || !buflen) break;
5533 max_level = get_max_level( format );
5535 switch(ft_face->glyph->format) {
5536 case ft_glyph_format_bitmap:
5538 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5539 INT h = ft_face->glyph->bitmap.rows;
5541 memset( buf, 0, needed );
5543 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5544 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5545 src += ft_face->glyph->bitmap.pitch;
5550 case ft_glyph_format_outline:
5552 ft_bitmap.width = width;
5553 ft_bitmap.rows = height;
5554 ft_bitmap.pitch = pitch;
5555 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5556 ft_bitmap.buffer = buf;
5559 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5561 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5563 memset(ft_bitmap.buffer, 0, buflen);
5565 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5567 if (max_level != 255)
5569 for (row = 0, start = buf; row < height; row++)
5571 for (col = 0, ptr = start; col < width; col++, ptr++)
5572 *ptr = (((int)*ptr) * max_level + 128) / 256;
5580 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5586 case WINE_GGO_HRGB_BITMAP:
5587 case WINE_GGO_HBGR_BITMAP:
5588 case WINE_GGO_VRGB_BITMAP:
5589 case WINE_GGO_VBGR_BITMAP:
5590 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5592 switch (ft_face->glyph->format)
5594 case FT_GLYPH_FORMAT_BITMAP:
5599 width = lpgm->gmBlackBoxX;
5600 height = lpgm->gmBlackBoxY;
5602 needed = pitch * height;
5604 if (!buf || !buflen) break;
5606 memset(buf, 0, buflen);
5608 src = ft_face->glyph->bitmap.buffer;
5609 src_pitch = ft_face->glyph->bitmap.pitch;
5611 height = min( height, ft_face->glyph->bitmap.rows );
5614 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5616 if ( src[x / 8] & masks[x % 8] )
5617 ((unsigned int *)dst)[x] = ~0u;
5626 case FT_GLYPH_FORMAT_OUTLINE:
5630 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5631 INT x_shift, y_shift;
5633 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5634 FT_Render_Mode render_mode =
5635 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5636 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5638 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5640 if ( render_mode == FT_RENDER_MODE_LCD)
5642 lpgm->gmBlackBoxX += 2;
5643 lpgm->gmptGlyphOrigin.x -= 1;
5647 lpgm->gmBlackBoxY += 2;
5648 lpgm->gmptGlyphOrigin.y += 1;
5652 width = lpgm->gmBlackBoxX;
5653 height = lpgm->gmBlackBoxY;
5655 needed = pitch * height;
5657 if (!buf || !buflen) break;
5659 memset(buf, 0, buflen);
5661 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5663 if ( needsTransform )
5664 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5666 if ( pFT_Library_SetLcdFilter )
5667 pFT_Library_SetLcdFilter( library, lcdfilter );
5668 pFT_Render_Glyph (ft_face->glyph, render_mode);
5670 src = ft_face->glyph->bitmap.buffer;
5671 src_pitch = ft_face->glyph->bitmap.pitch;
5672 src_width = ft_face->glyph->bitmap.width;
5673 src_height = ft_face->glyph->bitmap.rows;
5675 if ( render_mode == FT_RENDER_MODE_LCD)
5683 rgb_interval = src_pitch;
5688 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5689 if ( x_shift < 0 ) x_shift = 0;
5690 if ( x_shift + (src_width / hmul) > width )
5691 x_shift = width - (src_width / hmul);
5693 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5694 if ( y_shift < 0 ) y_shift = 0;
5695 if ( y_shift + (src_height / vmul) > height )
5696 y_shift = height - (src_height / vmul);
5698 dst += x_shift + y_shift * ( pitch / 4 );
5699 while ( src_height )
5701 for ( x = 0; x < src_width / hmul; x++ )
5705 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5706 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5707 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5708 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5712 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5713 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5714 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5715 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5718 src += src_pitch * vmul;
5727 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5739 int contour, point = 0, first_pt;
5740 FT_Outline *outline = &ft_face->glyph->outline;
5741 TTPOLYGONHEADER *pph;
5743 DWORD pph_start, cpfx, type;
5745 if(buflen == 0) buf = NULL;
5747 if (needsTransform && buf) {
5748 pFT_Outline_Transform(outline, &transMat);
5751 for(contour = 0; contour < outline->n_contours; contour++) {
5753 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5756 pph->dwType = TT_POLYGON_TYPE;
5757 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5759 needed += sizeof(*pph);
5761 while(point <= outline->contours[contour]) {
5762 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5763 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5764 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5768 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5771 } while(point <= outline->contours[contour] &&
5772 (outline->tags[point] & FT_Curve_Tag_On) ==
5773 (outline->tags[point-1] & FT_Curve_Tag_On));
5774 /* At the end of a contour Windows adds the start point, but
5776 if(point > outline->contours[contour] &&
5777 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5779 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5781 } else if(point <= outline->contours[contour] &&
5782 outline->tags[point] & FT_Curve_Tag_On) {
5783 /* add closing pt for bezier */
5785 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5793 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5796 pph->cb = needed - pph_start;
5802 /* Convert the quadratic Beziers to cubic Beziers.
5803 The parametric eqn for a cubic Bezier is, from PLRM:
5804 r(t) = at^3 + bt^2 + ct + r0
5805 with the control points:
5810 A quadratic Bezier has the form:
5811 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5813 So equating powers of t leads to:
5814 r1 = 2/3 p1 + 1/3 p0
5815 r2 = 2/3 p1 + 1/3 p2
5816 and of course r0 = p0, r3 = p2
5819 int contour, point = 0, first_pt;
5820 FT_Outline *outline = &ft_face->glyph->outline;
5821 TTPOLYGONHEADER *pph;
5823 DWORD pph_start, cpfx, type;
5824 FT_Vector cubic_control[4];
5825 if(buflen == 0) buf = NULL;
5827 if (needsTransform && buf) {
5828 pFT_Outline_Transform(outline, &transMat);
5831 for(contour = 0; contour < outline->n_contours; contour++) {
5833 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5836 pph->dwType = TT_POLYGON_TYPE;
5837 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5839 needed += sizeof(*pph);
5841 while(point <= outline->contours[contour]) {
5842 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5843 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5844 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5847 if(type == TT_PRIM_LINE) {
5849 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5853 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5856 /* FIXME: Possible optimization in endpoint calculation
5857 if there are two consecutive curves */
5858 cubic_control[0] = outline->points[point-1];
5859 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5860 cubic_control[0].x += outline->points[point].x + 1;
5861 cubic_control[0].y += outline->points[point].y + 1;
5862 cubic_control[0].x >>= 1;
5863 cubic_control[0].y >>= 1;
5865 if(point+1 > outline->contours[contour])
5866 cubic_control[3] = outline->points[first_pt];
5868 cubic_control[3] = outline->points[point+1];
5869 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5870 cubic_control[3].x += outline->points[point].x + 1;
5871 cubic_control[3].y += outline->points[point].y + 1;
5872 cubic_control[3].x >>= 1;
5873 cubic_control[3].y >>= 1;
5876 /* r1 = 1/3 p0 + 2/3 p1
5877 r2 = 1/3 p2 + 2/3 p1 */
5878 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5879 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5880 cubic_control[2] = cubic_control[1];
5881 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5882 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5883 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5884 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5886 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5887 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5888 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5893 } while(point <= outline->contours[contour] &&
5894 (outline->tags[point] & FT_Curve_Tag_On) ==
5895 (outline->tags[point-1] & FT_Curve_Tag_On));
5896 /* At the end of a contour Windows adds the start point,
5897 but only for Beziers and we've already done that.
5899 if(point <= outline->contours[contour] &&
5900 outline->tags[point] & FT_Curve_Tag_On) {
5901 /* This is the closing pt of a bezier, but we've already
5902 added it, so just inc point and carry on */
5909 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5912 pph->cb = needed - pph_start;
5918 FIXME("Unsupported format %d\n", format);
5924 static BOOL get_bitmap_text_metrics(GdiFont *font)
5926 FT_Face ft_face = font->ft_face;
5927 FT_WinFNT_HeaderRec winfnt_header;
5928 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5929 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5930 font->potm->otmSize = size;
5932 #define TM font->potm->otmTextMetrics
5933 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5935 TM.tmHeight = winfnt_header.pixel_height;
5936 TM.tmAscent = winfnt_header.ascent;
5937 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5938 TM.tmInternalLeading = winfnt_header.internal_leading;
5939 TM.tmExternalLeading = winfnt_header.external_leading;
5940 TM.tmAveCharWidth = winfnt_header.avg_width;
5941 TM.tmMaxCharWidth = winfnt_header.max_width;
5942 TM.tmWeight = winfnt_header.weight;
5944 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5945 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5946 TM.tmFirstChar = winfnt_header.first_char;
5947 TM.tmLastChar = winfnt_header.last_char;
5948 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5949 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5950 TM.tmItalic = winfnt_header.italic;
5951 TM.tmUnderlined = font->underline;
5952 TM.tmStruckOut = font->strikeout;
5953 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5954 TM.tmCharSet = winfnt_header.charset;
5958 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5959 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5960 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5961 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5962 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5963 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5964 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5965 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5967 TM.tmDigitizedAspectX = 96; /* FIXME */
5968 TM.tmDigitizedAspectY = 96; /* FIXME */
5970 TM.tmLastChar = 255;
5971 TM.tmDefaultChar = 32;
5972 TM.tmBreakChar = 32;
5973 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5974 TM.tmUnderlined = font->underline;
5975 TM.tmStruckOut = font->strikeout;
5976 /* NB inverted meaning of TMPF_FIXED_PITCH */
5977 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5978 TM.tmCharSet = font->charset;
5986 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5988 double scale_x, scale_y;
5992 scale_x = (double)font->aveWidth;
5993 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5996 scale_x = font->scale_y;
5998 scale_x *= fabs(font->font_desc.matrix.eM11);
5999 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6001 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6002 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6004 SCALE_Y(ptm->tmHeight);
6005 SCALE_Y(ptm->tmAscent);
6006 SCALE_Y(ptm->tmDescent);
6007 SCALE_Y(ptm->tmInternalLeading);
6008 SCALE_Y(ptm->tmExternalLeading);
6009 SCALE_Y(ptm->tmOverhang);
6011 SCALE_X(ptm->tmAveCharWidth);
6012 SCALE_X(ptm->tmMaxCharWidth);
6018 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6020 double scale_x, scale_y;
6024 scale_x = (double)font->aveWidth;
6025 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6028 scale_x = font->scale_y;
6030 scale_x *= fabs(font->font_desc.matrix.eM11);
6031 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6033 scale_font_metrics(font, &potm->otmTextMetrics);
6035 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6036 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6038 SCALE_Y(potm->otmAscent);
6039 SCALE_Y(potm->otmDescent);
6040 SCALE_Y(potm->otmLineGap);
6041 SCALE_Y(potm->otmsCapEmHeight);
6042 SCALE_Y(potm->otmsXHeight);
6043 SCALE_Y(potm->otmrcFontBox.top);
6044 SCALE_Y(potm->otmrcFontBox.bottom);
6045 SCALE_X(potm->otmrcFontBox.left);
6046 SCALE_X(potm->otmrcFontBox.right);
6047 SCALE_Y(potm->otmMacAscent);
6048 SCALE_Y(potm->otmMacDescent);
6049 SCALE_Y(potm->otmMacLineGap);
6050 SCALE_X(potm->otmptSubscriptSize.x);
6051 SCALE_Y(potm->otmptSubscriptSize.y);
6052 SCALE_X(potm->otmptSubscriptOffset.x);
6053 SCALE_Y(potm->otmptSubscriptOffset.y);
6054 SCALE_X(potm->otmptSuperscriptSize.x);
6055 SCALE_Y(potm->otmptSuperscriptSize.y);
6056 SCALE_X(potm->otmptSuperscriptOffset.x);
6057 SCALE_Y(potm->otmptSuperscriptOffset.y);
6058 SCALE_Y(potm->otmsStrikeoutSize);
6059 SCALE_Y(potm->otmsStrikeoutPosition);
6060 SCALE_Y(potm->otmsUnderscoreSize);
6061 SCALE_Y(potm->otmsUnderscorePosition);
6067 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6071 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6073 /* Make sure that the font has sane width/height ratio */
6076 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6078 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6083 *ptm = font->potm->otmTextMetrics;
6084 scale_font_metrics(font, ptm);
6088 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6092 for(i = 0; i < ft_face->num_charmaps; i++)
6094 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6100 static BOOL get_outline_text_metrics(GdiFont *font)
6103 FT_Face ft_face = font->ft_face;
6104 UINT needed, lenfam, lensty;
6106 TT_HoriHeader *pHori;
6107 TT_Postscript *pPost;
6108 FT_Fixed x_scale, y_scale;
6109 WCHAR *family_nameW, *style_nameW;
6110 static const WCHAR spaceW[] = {' ', '\0'};
6112 INT ascent, descent;
6114 TRACE("font=%p\n", font);
6116 if(!FT_IS_SCALABLE(ft_face))
6119 needed = sizeof(*font->potm);
6121 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6122 family_nameW = strdupW(font->name);
6124 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6126 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6127 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6128 style_nameW, lensty/sizeof(WCHAR));
6130 /* These names should be read from the TT name table */
6132 /* length of otmpFamilyName */
6135 /* length of otmpFaceName */
6136 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6137 needed += lenfam; /* just the family name */
6139 needed += lenfam + lensty; /* family + " " + style */
6142 /* length of otmpStyleName */
6145 /* length of otmpFullName */
6146 needed += lenfam + lensty;
6149 x_scale = ft_face->size->metrics.x_scale;
6150 y_scale = ft_face->size->metrics.y_scale;
6152 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6154 FIXME("Can't find OS/2 table - not TT font?\n");
6158 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6160 FIXME("Can't find HHEA table - not TT font?\n");
6164 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6166 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",
6167 pOS2->usWinAscent, pOS2->usWinDescent,
6168 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6169 ft_face->ascender, ft_face->descender, ft_face->height,
6170 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6171 ft_face->bbox.yMax, ft_face->bbox.yMin);
6173 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6174 font->potm->otmSize = needed;
6176 #define TM font->potm->otmTextMetrics
6178 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6179 ascent = pHori->Ascender;
6180 descent = -pHori->Descender;
6182 ascent = pOS2->usWinAscent;
6183 descent = pOS2->usWinDescent;
6187 TM.tmAscent = font->yMax;
6188 TM.tmDescent = -font->yMin;
6189 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6191 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6192 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6193 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6194 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6197 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6200 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6202 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6203 ((ascent + descent) -
6204 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6206 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6207 if (TM.tmAveCharWidth == 0) {
6208 TM.tmAveCharWidth = 1;
6210 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6211 TM.tmWeight = FW_REGULAR;
6212 if (font->fake_bold)
6213 TM.tmWeight = FW_BOLD;
6216 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6218 if (pOS2->usWeightClass > FW_MEDIUM)
6219 TM.tmWeight = pOS2->usWeightClass;
6221 else if (pOS2->usWeightClass <= FW_MEDIUM)
6222 TM.tmWeight = pOS2->usWeightClass;
6225 TM.tmDigitizedAspectX = 300;
6226 TM.tmDigitizedAspectY = 300;
6227 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6228 * symbol range to 0 - f0ff
6231 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6236 case 1257: /* Baltic */
6237 TM.tmLastChar = 0xf8fd;
6240 TM.tmLastChar = 0xf0ff;
6242 TM.tmBreakChar = 0x20;
6243 TM.tmDefaultChar = 0x1f;
6247 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6248 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6250 if(pOS2->usFirstCharIndex <= 1)
6251 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6252 else if (pOS2->usFirstCharIndex > 0xff)
6253 TM.tmBreakChar = 0x20;
6255 TM.tmBreakChar = pOS2->usFirstCharIndex;
6256 TM.tmDefaultChar = TM.tmBreakChar - 1;
6258 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6259 TM.tmUnderlined = font->underline;
6260 TM.tmStruckOut = font->strikeout;
6262 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6263 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6264 (pOS2->version == 0xFFFFU ||
6265 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6266 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6268 TM.tmPitchAndFamily = 0;
6270 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6272 case PAN_FAMILY_SCRIPT:
6273 TM.tmPitchAndFamily |= FF_SCRIPT;
6276 case PAN_FAMILY_DECORATIVE:
6277 TM.tmPitchAndFamily |= FF_DECORATIVE;
6282 case PAN_FAMILY_TEXT_DISPLAY:
6283 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6284 /* which is clearly not what the panose spec says. */
6286 if(TM.tmPitchAndFamily == 0 || /* fixed */
6287 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6288 TM.tmPitchAndFamily = FF_MODERN;
6291 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6296 TM.tmPitchAndFamily |= FF_DONTCARE;
6299 case PAN_SERIF_COVE:
6300 case PAN_SERIF_OBTUSE_COVE:
6301 case PAN_SERIF_SQUARE_COVE:
6302 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6303 case PAN_SERIF_SQUARE:
6304 case PAN_SERIF_THIN:
6305 case PAN_SERIF_BONE:
6306 case PAN_SERIF_EXAGGERATED:
6307 case PAN_SERIF_TRIANGLE:
6308 TM.tmPitchAndFamily |= FF_ROMAN;
6311 case PAN_SERIF_NORMAL_SANS:
6312 case PAN_SERIF_OBTUSE_SANS:
6313 case PAN_SERIF_PERP_SANS:
6314 case PAN_SERIF_FLARED:
6315 case PAN_SERIF_ROUNDED:
6316 TM.tmPitchAndFamily |= FF_SWISS;
6323 if(FT_IS_SCALABLE(ft_face))
6324 TM.tmPitchAndFamily |= TMPF_VECTOR;
6326 if(FT_IS_SFNT(ft_face))
6328 if (font->ntmFlags & NTM_PS_OPENTYPE)
6329 TM.tmPitchAndFamily |= TMPF_DEVICE;
6331 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6334 TM.tmCharSet = font->charset;
6336 font->potm->otmFiller = 0;
6337 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6338 font->potm->otmfsSelection = pOS2->fsSelection;
6339 font->potm->otmfsType = pOS2->fsType;
6340 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6341 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6342 font->potm->otmItalicAngle = 0; /* POST table */
6343 font->potm->otmEMSquare = ft_face->units_per_EM;
6344 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6345 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6346 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6347 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6348 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6349 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6350 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6351 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6352 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6353 font->potm->otmMacAscent = TM.tmAscent;
6354 font->potm->otmMacDescent = -TM.tmDescent;
6355 font->potm->otmMacLineGap = font->potm->otmLineGap;
6356 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6357 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6358 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6359 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6360 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6361 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6362 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6363 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6364 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6365 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6366 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6368 font->potm->otmsUnderscoreSize = 0;
6369 font->potm->otmsUnderscorePosition = 0;
6371 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6372 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6376 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6377 cp = (char*)font->potm + sizeof(*font->potm);
6378 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6379 strcpyW((WCHAR*)cp, family_nameW);
6381 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6382 strcpyW((WCHAR*)cp, style_nameW);
6384 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6385 strcpyW((WCHAR*)cp, family_nameW);
6386 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6387 strcatW((WCHAR*)cp, spaceW);
6388 strcatW((WCHAR*)cp, style_nameW);
6389 cp += lenfam + lensty;
6392 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6393 strcpyW((WCHAR*)cp, family_nameW);
6394 strcatW((WCHAR*)cp, spaceW);
6395 strcatW((WCHAR*)cp, style_nameW);
6399 HeapFree(GetProcessHeap(), 0, style_nameW);
6400 HeapFree(GetProcessHeap(), 0, family_nameW);
6404 /*************************************************************
6405 * freetype_GetGlyphOutline
6407 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6408 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6410 struct freetype_physdev *physdev = get_freetype_dev( dev );
6415 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6416 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6420 EnterCriticalSection( &freetype_cs );
6421 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6422 LeaveCriticalSection( &freetype_cs );
6426 /*************************************************************
6427 * freetype_GetTextMetrics
6429 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6431 struct freetype_physdev *physdev = get_freetype_dev( dev );
6436 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6437 return dev->funcs->pGetTextMetrics( dev, metrics );
6441 EnterCriticalSection( &freetype_cs );
6442 ret = get_text_metrics( physdev->font, metrics );
6443 LeaveCriticalSection( &freetype_cs );
6447 /*************************************************************
6448 * freetype_GetOutlineTextMetrics
6450 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6452 struct freetype_physdev *physdev = get_freetype_dev( dev );
6457 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6458 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6461 TRACE("font=%p\n", physdev->font);
6463 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6466 EnterCriticalSection( &freetype_cs );
6468 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6470 if(cbSize >= physdev->font->potm->otmSize)
6472 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6473 scale_outline_font_metrics(physdev->font, potm);
6475 ret = physdev->font->potm->otmSize;
6477 LeaveCriticalSection( &freetype_cs );
6481 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6483 HFONTLIST *hfontlist;
6484 child->font = alloc_font();
6485 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6486 if(!child->font->ft_face)
6488 free_font(child->font);
6493 child->font->font_desc = font->font_desc;
6494 child->font->ntmFlags = child->face->ntmFlags;
6495 child->font->orientation = font->orientation;
6496 child->font->scale_y = font->scale_y;
6497 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6498 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6499 child->font->name = strdupW(child->face->family->FamilyName);
6500 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6501 child->font->base_font = font;
6502 list_add_head(&child_font_list, &child->font->entry);
6503 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6507 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6510 CHILD_FONT *child_font;
6513 font = font->base_font;
6515 *linked_font = font;
6517 if((*glyph = get_glyph_index(font, c)))
6519 *glyph = get_GSUB_vert_glyph(font, *glyph);
6523 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6525 if(!child_font->font)
6526 if(!load_child_font(font, child_font))
6529 if(!child_font->font->ft_face)
6531 g = get_glyph_index(child_font->font, c);
6532 g = get_GSUB_vert_glyph(child_font->font, g);
6536 *linked_font = child_font->font;
6543 /*************************************************************
6544 * freetype_GetCharWidth
6546 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6548 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6551 FT_UInt glyph_index;
6552 GdiFont *linked_font;
6553 struct freetype_physdev *physdev = get_freetype_dev( dev );
6557 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6558 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6561 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6564 EnterCriticalSection( &freetype_cs );
6565 for(c = firstChar; c <= lastChar; c++) {
6566 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6567 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6568 &gm, 0, NULL, &identity);
6569 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6571 LeaveCriticalSection( &freetype_cs );
6575 /*************************************************************
6576 * freetype_GetCharABCWidths
6578 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6580 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6583 FT_UInt glyph_index;
6584 GdiFont *linked_font;
6585 struct freetype_physdev *physdev = get_freetype_dev( dev );
6589 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6590 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6593 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6596 EnterCriticalSection( &freetype_cs );
6598 for(c = firstChar; c <= lastChar; c++) {
6599 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6600 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6601 &gm, 0, NULL, &identity);
6602 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6603 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6604 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6605 FONT_GM(linked_font,glyph_index)->bbx;
6607 LeaveCriticalSection( &freetype_cs );
6611 /*************************************************************
6612 * freetype_GetCharABCWidthsI
6614 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6616 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6619 FT_UInt glyph_index;
6620 GdiFont *linked_font;
6621 struct freetype_physdev *physdev = get_freetype_dev( dev );
6625 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6626 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6629 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6633 EnterCriticalSection( &freetype_cs );
6635 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6637 for(c = firstChar; c < firstChar+count; c++) {
6638 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6639 &gm, 0, NULL, &identity);
6640 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6641 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6642 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6643 - FONT_GM(linked_font,c)->bbx;
6646 for(c = 0; c < count; c++) {
6647 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6648 &gm, 0, NULL, &identity);
6649 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6650 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6651 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6652 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6655 LeaveCriticalSection( &freetype_cs );
6659 /*************************************************************
6660 * freetype_GetTextExtentExPoint
6662 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6663 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6665 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6670 FT_UInt glyph_index;
6671 GdiFont *linked_font;
6672 struct freetype_physdev *physdev = get_freetype_dev( dev );
6676 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6677 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6680 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6683 EnterCriticalSection( &freetype_cs );
6686 get_text_metrics( physdev->font, &tm );
6687 size->cy = tm.tmHeight;
6689 for(idx = 0; idx < count; idx++) {
6690 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6691 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6692 &gm, 0, NULL, &identity);
6693 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6695 if (! pnfit || ext <= max_ext) {
6705 LeaveCriticalSection( &freetype_cs );
6706 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6710 /*************************************************************
6711 * freetype_GetTextExtentExPointI
6713 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6714 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6716 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6721 struct freetype_physdev *physdev = get_freetype_dev( dev );
6725 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6726 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6729 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6732 EnterCriticalSection( &freetype_cs );
6735 get_text_metrics(physdev->font, &tm);
6736 size->cy = tm.tmHeight;
6738 for(idx = 0; idx < count; idx++) {
6739 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6740 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6742 if (! pnfit || ext <= max_ext) {
6752 LeaveCriticalSection( &freetype_cs );
6753 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6757 /*************************************************************
6758 * freetype_GetFontData
6760 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6762 struct freetype_physdev *physdev = get_freetype_dev( dev );
6766 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6767 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6770 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6771 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6772 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6774 return get_font_data( physdev->font, table, offset, buf, cbData );
6777 /*************************************************************
6778 * freetype_GetTextFace
6780 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6783 struct freetype_physdev *physdev = get_freetype_dev( dev );
6787 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6788 return dev->funcs->pGetTextFace( dev, count, str );
6791 n = strlenW(physdev->font->name) + 1;
6794 lstrcpynW(str, physdev->font->name, count);
6800 /*************************************************************
6801 * freetype_GetTextCharsetInfo
6803 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6805 struct freetype_physdev *physdev = get_freetype_dev( dev );
6809 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6810 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6812 if (fs) *fs = physdev->font->fs;
6813 return physdev->font->charset;
6816 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6818 GdiFont *font = dc->gdiFont, *linked_font;
6819 struct list *first_hfont;
6823 EnterCriticalSection( &freetype_cs );
6824 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6825 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6826 if(font == linked_font)
6827 *new_hfont = dc->hFont;
6830 first_hfont = list_head(&linked_font->hfontlist);
6831 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6833 LeaveCriticalSection( &freetype_cs );
6837 /* Retrieve a list of supported Unicode ranges for a given font.
6838 * Can be called with NULL gs to calculate the buffer size. Returns
6839 * the number of ranges found.
6841 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6843 DWORD num_ranges = 0;
6845 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6848 FT_ULong char_code, char_code_prev;
6851 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6853 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6854 face->num_glyphs, glyph_code, char_code);
6856 if (!glyph_code) return 0;
6860 gs->ranges[0].wcLow = (USHORT)char_code;
6861 gs->ranges[0].cGlyphs = 0;
6862 gs->cGlyphsSupported = 0;
6868 if (char_code < char_code_prev)
6870 ERR("expected increasing char code from FT_Get_Next_Char\n");
6873 if (char_code - char_code_prev > 1)
6878 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6879 gs->ranges[num_ranges - 1].cGlyphs = 1;
6880 gs->cGlyphsSupported++;
6885 gs->ranges[num_ranges - 1].cGlyphs++;
6886 gs->cGlyphsSupported++;
6888 char_code_prev = char_code;
6889 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6893 FIXME("encoding %u not supported\n", face->charmap->encoding);
6898 /*************************************************************
6899 * freetype_GetFontUnicodeRanges
6901 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6903 struct freetype_physdev *physdev = get_freetype_dev( dev );
6904 DWORD size, num_ranges;
6908 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6909 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6912 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6913 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6916 glyphset->cbThis = size;
6917 glyphset->cRanges = num_ranges;
6918 glyphset->flAccel = 0;
6923 /*************************************************************
6924 * freetype_FontIsLinked
6926 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6928 struct freetype_physdev *physdev = get_freetype_dev( dev );
6933 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6934 return dev->funcs->pFontIsLinked( dev );
6938 EnterCriticalSection( &freetype_cs );
6939 ret = !list_empty(&physdev->font->child_fonts);
6940 LeaveCriticalSection( &freetype_cs );
6944 static BOOL is_hinting_enabled(void)
6946 /* Use the >= 2.2.0 function if available */
6947 if(pFT_Get_TrueType_Engine_Type)
6949 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6950 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6952 #ifdef FT_DRIVER_HAS_HINTER
6957 /* otherwise if we've been compiled with < 2.2.0 headers
6958 use the internal macro */
6959 mod = pFT_Get_Module(library, "truetype");
6960 if(mod && FT_DRIVER_HAS_HINTER(mod))
6968 static BOOL is_subpixel_rendering_enabled( void )
6970 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6971 return pFT_Library_SetLcdFilter &&
6972 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6978 /*************************************************************************
6979 * GetRasterizerCaps (GDI32.@)
6981 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6983 static int hinting = -1;
6984 static int subpixel = -1;
6988 hinting = is_hinting_enabled();
6989 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6992 if ( subpixel == -1 )
6994 subpixel = is_subpixel_rendering_enabled();
6995 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6998 lprs->nSize = sizeof(RASTERIZER_STATUS);
6999 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7001 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7002 lprs->nLanguageID = 0;
7006 /*************************************************************
7007 * freetype_GdiRealizationInfo
7009 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7011 struct freetype_physdev *physdev = get_freetype_dev( dev );
7012 realization_info_t *info = ptr;
7016 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7017 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7020 FIXME("(%p, %p): stub!\n", physdev->font, info);
7023 if(FT_IS_SCALABLE(physdev->font->ft_face))
7026 info->cache_num = physdev->font->cache_num;
7027 info->unknown2 = -1;
7031 /*************************************************************************
7032 * Kerning support for TrueType fonts
7034 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7036 struct TT_kern_table
7042 struct TT_kern_subtable
7051 USHORT horizontal : 1;
7053 USHORT cross_stream: 1;
7054 USHORT override : 1;
7055 USHORT reserved1 : 4;
7061 struct TT_format0_kern_subtable
7065 USHORT entrySelector;
7076 static DWORD parse_format0_kern_subtable(GdiFont *font,
7077 const struct TT_format0_kern_subtable *tt_f0_ks,
7078 const USHORT *glyph_to_char,
7079 KERNINGPAIR *kern_pair, DWORD cPairs)
7082 const struct TT_kern_pair *tt_kern_pair;
7084 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7086 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7088 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7089 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7090 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7092 if (!kern_pair || !cPairs)
7095 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7097 nPairs = min(nPairs, cPairs);
7099 for (i = 0; i < nPairs; i++)
7101 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7102 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7103 /* this algorithm appears to better match what Windows does */
7104 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7105 if (kern_pair->iKernAmount < 0)
7107 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7108 kern_pair->iKernAmount -= font->ppem;
7110 else if (kern_pair->iKernAmount > 0)
7112 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7113 kern_pair->iKernAmount += font->ppem;
7115 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7117 TRACE("left %u right %u value %d\n",
7118 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7122 TRACE("copied %u entries\n", nPairs);
7126 /*************************************************************
7127 * freetype_GetKerningPairs
7129 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7133 const struct TT_kern_table *tt_kern_table;
7134 const struct TT_kern_subtable *tt_kern_subtable;
7136 USHORT *glyph_to_char;
7138 struct freetype_physdev *physdev = get_freetype_dev( dev );
7140 if (!(font = physdev->font))
7142 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7143 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7147 EnterCriticalSection( &freetype_cs );
7148 if (font->total_kern_pairs != (DWORD)-1)
7150 if (cPairs && kern_pair)
7152 cPairs = min(cPairs, font->total_kern_pairs);
7153 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7155 else cPairs = font->total_kern_pairs;
7157 LeaveCriticalSection( &freetype_cs );
7161 font->total_kern_pairs = 0;
7163 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7165 if (length == GDI_ERROR)
7167 TRACE("no kerning data in the font\n");
7168 LeaveCriticalSection( &freetype_cs );
7172 buf = HeapAlloc(GetProcessHeap(), 0, length);
7175 WARN("Out of memory\n");
7176 LeaveCriticalSection( &freetype_cs );
7180 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7182 /* build a glyph index to char code map */
7183 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7186 WARN("Out of memory allocating a glyph index to char code map\n");
7187 HeapFree(GetProcessHeap(), 0, buf);
7188 LeaveCriticalSection( &freetype_cs );
7192 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7198 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7200 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7201 font->ft_face->num_glyphs, glyph_code, char_code);
7205 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7207 /* FIXME: This doesn't match what Windows does: it does some fancy
7208 * things with duplicate glyph index to char code mappings, while
7209 * we just avoid overriding existing entries.
7211 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7212 glyph_to_char[glyph_code] = (USHORT)char_code;
7214 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7221 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7222 for (n = 0; n <= 65535; n++)
7223 glyph_to_char[n] = (USHORT)n;
7226 tt_kern_table = buf;
7227 nTables = GET_BE_WORD(tt_kern_table->nTables);
7228 TRACE("version %u, nTables %u\n",
7229 GET_BE_WORD(tt_kern_table->version), nTables);
7231 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7233 for (i = 0; i < nTables; i++)
7235 struct TT_kern_subtable tt_kern_subtable_copy;
7237 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7238 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7239 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7241 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7242 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7243 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7245 /* According to the TrueType specification this is the only format
7246 * that will be properly interpreted by Windows and OS/2
7248 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7250 DWORD new_chunk, old_total = font->total_kern_pairs;
7252 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7253 glyph_to_char, NULL, 0);
7254 font->total_kern_pairs += new_chunk;
7256 if (!font->kern_pairs)
7257 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7258 font->total_kern_pairs * sizeof(*font->kern_pairs));
7260 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7261 font->total_kern_pairs * sizeof(*font->kern_pairs));
7263 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7264 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7267 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7269 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7272 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7273 HeapFree(GetProcessHeap(), 0, buf);
7275 if (cPairs && kern_pair)
7277 cPairs = min(cPairs, font->total_kern_pairs);
7278 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7280 else cPairs = font->total_kern_pairs;
7282 LeaveCriticalSection( &freetype_cs );
7286 static const struct gdi_dc_funcs freetype_funcs =
7288 NULL, /* pAbortDoc */
7289 NULL, /* pAbortPath */
7290 NULL, /* pAlphaBlend */
7291 NULL, /* pAngleArc */
7294 NULL, /* pBeginPath */
7295 NULL, /* pBlendImage */
7296 NULL, /* pChoosePixelFormat */
7298 NULL, /* pCloseFigure */
7299 NULL, /* pCopyBitmap */
7300 NULL, /* pCreateBitmap */
7301 NULL, /* pCreateCompatibleDC */
7302 freetype_CreateDC, /* pCreateDC */
7303 NULL, /* pDeleteBitmap */
7304 freetype_DeleteDC, /* pDeleteDC */
7305 NULL, /* pDeleteObject */
7306 NULL, /* pDescribePixelFormat */
7307 NULL, /* pDeviceCapabilities */
7308 NULL, /* pEllipse */
7310 NULL, /* pEndPage */
7311 NULL, /* pEndPath */
7312 freetype_EnumFonts, /* pEnumFonts */
7313 NULL, /* pEnumICMProfiles */
7314 NULL, /* pExcludeClipRect */
7315 NULL, /* pExtDeviceMode */
7316 NULL, /* pExtEscape */
7317 NULL, /* pExtFloodFill */
7318 NULL, /* pExtSelectClipRgn */
7319 NULL, /* pExtTextOut */
7320 NULL, /* pFillPath */
7321 NULL, /* pFillRgn */
7322 NULL, /* pFlattenPath */
7323 freetype_FontIsLinked, /* pFontIsLinked */
7324 NULL, /* pFrameRgn */
7325 NULL, /* pGdiComment */
7326 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7327 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7328 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7329 freetype_GetCharWidth, /* pGetCharWidth */
7330 NULL, /* pGetDeviceCaps */
7331 NULL, /* pGetDeviceGammaRamp */
7332 freetype_GetFontData, /* pGetFontData */
7333 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7334 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7335 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7336 NULL, /* pGetICMProfile */
7337 NULL, /* pGetImage */
7338 freetype_GetKerningPairs, /* pGetKerningPairs */
7339 NULL, /* pGetNearestColor */
7340 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7341 NULL, /* pGetPixel */
7342 NULL, /* pGetPixelFormat */
7343 NULL, /* pGetSystemPaletteEntries */
7344 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7345 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7346 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7347 freetype_GetTextFace, /* pGetTextFace */
7348 freetype_GetTextMetrics, /* pGetTextMetrics */
7349 NULL, /* pGradientFill */
7350 NULL, /* pIntersectClipRect */
7351 NULL, /* pInvertRgn */
7353 NULL, /* pModifyWorldTransform */
7355 NULL, /* pOffsetClipRgn */
7356 NULL, /* pOffsetViewportOrg */
7357 NULL, /* pOffsetWindowOrg */
7358 NULL, /* pPaintRgn */
7361 NULL, /* pPolyBezier */
7362 NULL, /* pPolyBezierTo */
7363 NULL, /* pPolyDraw */
7364 NULL, /* pPolyPolygon */
7365 NULL, /* pPolyPolyline */
7366 NULL, /* pPolygon */
7367 NULL, /* pPolyline */
7368 NULL, /* pPolylineTo */
7369 NULL, /* pPutImage */
7370 NULL, /* pRealizeDefaultPalette */
7371 NULL, /* pRealizePalette */
7372 NULL, /* pRectangle */
7373 NULL, /* pResetDC */
7374 NULL, /* pRestoreDC */
7375 NULL, /* pRoundRect */
7377 NULL, /* pScaleViewportExt */
7378 NULL, /* pScaleWindowExt */
7379 NULL, /* pSelectBitmap */
7380 NULL, /* pSelectBrush */
7381 NULL, /* pSelectClipPath */
7382 freetype_SelectFont, /* pSelectFont */
7383 NULL, /* pSelectPalette */
7384 NULL, /* pSelectPen */
7385 NULL, /* pSetArcDirection */
7386 NULL, /* pSetBkColor */
7387 NULL, /* pSetBkMode */
7388 NULL, /* pSetDCBrushColor */
7389 NULL, /* pSetDCPenColor */
7390 NULL, /* pSetDIBColorTable */
7391 NULL, /* pSetDIBitsToDevice */
7392 NULL, /* pSetDeviceClipping */
7393 NULL, /* pSetDeviceGammaRamp */
7394 NULL, /* pSetLayout */
7395 NULL, /* pSetMapMode */
7396 NULL, /* pSetMapperFlags */
7397 NULL, /* pSetPixel */
7398 NULL, /* pSetPixelFormat */
7399 NULL, /* pSetPolyFillMode */
7400 NULL, /* pSetROP2 */
7401 NULL, /* pSetRelAbs */
7402 NULL, /* pSetStretchBltMode */
7403 NULL, /* pSetTextAlign */
7404 NULL, /* pSetTextCharacterExtra */
7405 NULL, /* pSetTextColor */
7406 NULL, /* pSetTextJustification */
7407 NULL, /* pSetViewportExt */
7408 NULL, /* pSetViewportOrg */
7409 NULL, /* pSetWindowExt */
7410 NULL, /* pSetWindowOrg */
7411 NULL, /* pSetWorldTransform */
7412 NULL, /* pStartDoc */
7413 NULL, /* pStartPage */
7414 NULL, /* pStretchBlt */
7415 NULL, /* pStretchDIBits */
7416 NULL, /* pStrokeAndFillPath */
7417 NULL, /* pStrokePath */
7418 NULL, /* pSwapBuffers */
7419 NULL, /* pUnrealizePalette */
7420 NULL, /* pWidenPath */
7421 /* OpenGL not supported */
7424 #else /* HAVE_FREETYPE */
7426 /*************************************************************************/
7428 BOOL WineEngInit(void)
7432 BOOL WineEngDestroyFontInstance(HFONT hfont)
7437 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7439 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7443 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7445 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7449 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7451 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7455 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7460 /*************************************************************************
7461 * GetRasterizerCaps (GDI32.@)
7463 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7465 lprs->nSize = sizeof(RASTERIZER_STATUS);
7467 lprs->nLanguageID = 0;
7471 #endif /* HAVE_FREETYPE */