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 {
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;
345 UINT ntmCellHeight, ntmAvgWidth;
354 const WCHAR *font_name;
359 struct enum_charset_element {
362 WCHAR name[LF_FACESIZE];
365 struct enum_charset_list {
367 struct enum_charset_element element[32];
370 #define GM_BLOCK_SIZE 128
371 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
373 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
374 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
375 #define UNUSED_CACHE_SIZE 10
376 static struct list child_font_list = LIST_INIT(child_font_list);
377 static struct list system_links = LIST_INIT(system_links);
379 static struct list font_subst_list = LIST_INIT(font_subst_list);
381 static struct list font_list = LIST_INIT(font_list);
383 struct freetype_physdev
385 struct gdi_physdev dev;
389 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
391 return (struct freetype_physdev *)dev;
394 static const struct gdi_dc_funcs freetype_funcs;
396 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
397 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
398 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
400 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
401 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
402 'W','i','n','d','o','w','s','\\',
403 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
404 'F','o','n','t','s','\0'};
406 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
407 'W','i','n','d','o','w','s',' ','N','T','\\',
408 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
409 'F','o','n','t','s','\0'};
411 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
412 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
413 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
414 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
416 static const WCHAR * const SystemFontValues[] = {
423 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
424 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
426 /* Interesting and well-known (frequently-assumed!) font names */
427 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
428 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 };
429 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
430 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
431 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
432 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
433 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
434 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
436 static const WCHAR arial[] = {'A','r','i','a','l',0};
437 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
438 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};
439 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};
440 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
441 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
442 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
443 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
444 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
445 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
447 static const WCHAR *default_serif_list[] =
451 bitstream_vera_serif,
455 static const WCHAR *default_fixed_list[] =
459 bitstream_vera_sans_mono,
463 static const WCHAR *default_sans_list[] =
476 typedef struct tagFontSubst {
482 /* Registry font cache key and value names */
483 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
484 'F','o','n','t','s',0};
485 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
486 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
487 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
488 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
489 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','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 inline BOOL faces_equal( const Face *f1, const Face *f2 )
1195 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1196 if (f1->scalable) return TRUE;
1197 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1198 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1201 static inline void free_face( Face *face )
1203 HeapFree( GetProcessHeap(), 0, face->file );
1204 HeapFree( GetProcessHeap(), 0, face->StyleName );
1205 HeapFree( GetProcessHeap(), 0, face->FullName );
1206 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1207 HeapFree( GetProcessHeap(), 0, face );
1210 static inline void free_family( Family *family )
1212 Face *face, *cursor2;
1214 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1216 list_remove( &face->entry );
1219 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1220 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1221 HeapFree( GetProcessHeap(), 0, family );
1224 static inline int style_order(const Face *face)
1226 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1234 case NTM_BOLD | NTM_ITALIC:
1237 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1238 debugstr_w(face->family->FamilyName),
1239 debugstr_w(face->StyleName),
1245 static BOOL insert_face_in_family_list( Face *face, Family *family )
1249 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1251 if (faces_equal( face, cursor ))
1253 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1254 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1255 cursor->font_version, face->font_version);
1257 if (face->font_version <= cursor->font_version)
1259 TRACE("Original font %s is newer so skipping %s\n",
1260 debugstr_a(cursor->file), debugstr_a(face->file));
1265 TRACE("Replacing original %s with %s\n",
1266 debugstr_a(cursor->file), debugstr_a(face->file));
1267 list_add_before( &cursor->entry, &face->entry );
1268 face->family = family;
1269 list_remove( &cursor->entry);
1270 free_face( cursor );
1275 TRACE("Adding new %s\n", debugstr_a(face->file));
1277 if (style_order( face ) < style_order( cursor )) break;
1280 list_add_before( &cursor->entry, &face->entry );
1281 face->family = family;
1285 /****************************************************************
1286 * NB This function stores the ptrs to the strings to save copying.
1287 * Don't free them after calling.
1289 static Family *create_family( WCHAR *name, WCHAR *english_name )
1291 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1292 family->FamilyName = name;
1293 family->EnglishName = english_name;
1294 list_init( &family->faces );
1295 family->replacement = &family->faces;
1300 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1303 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1304 if(r != ERROR_SUCCESS) return r;
1305 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1306 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1309 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1311 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1314 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1317 DWORD num_strikes, max_strike_key_len;
1319 /* If we have a File Name key then this is a real font, not just the parent
1320 key of a bunch of non-scalable strikes */
1321 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1324 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1325 face->cached_enum_data = NULL;
1327 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1328 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1330 face->StyleName = strdupW(face_name);
1332 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1334 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1335 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1336 face->FullName = fullName;
1339 face->FullName = NULL;
1341 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1342 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1343 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1344 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1346 needed = sizeof(face->fs);
1347 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1349 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1351 face->scalable = TRUE;
1352 memset(&face->size, 0, sizeof(face->size));
1356 face->scalable = FALSE;
1357 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1358 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1359 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1360 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1361 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1363 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1364 face->size.height, face->size.width, face->size.size >> 6,
1365 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1368 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1369 face->fs.fsCsb[0], face->fs.fsCsb[1],
1370 face->fs.fsUsb[0], face->fs.fsUsb[1],
1371 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1373 insert_face_in_family_list(face, family);
1375 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1378 /* do we have any bitmap strikes? */
1379 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1380 NULL, NULL, NULL, NULL);
1381 if(num_strikes != 0)
1383 WCHAR strike_name[10];
1384 DWORD strike_index = 0;
1386 needed = sizeof(strike_name) / sizeof(WCHAR);
1387 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1388 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1391 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1392 load_face(hkey_strike, face_name, family);
1393 RegCloseKey(hkey_strike);
1394 needed = sizeof(strike_name) / sizeof(WCHAR);
1399 static void load_font_list_from_cache(HKEY hkey_font_cache)
1401 DWORD max_family_key_len, size;
1403 DWORD family_index = 0;
1407 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1408 NULL, NULL, NULL, NULL);
1409 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1411 size = max_family_key_len + 1;
1412 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1413 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1415 WCHAR *english_family = NULL;
1416 DWORD face_index = 0;
1418 DWORD max_face_key_len;
1420 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1421 TRACE("opened family key %s\n", debugstr_w(family_name));
1422 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1424 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1425 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1428 family = create_family(strdupW(family_name), english_family);
1429 list_add_tail(&font_list, &family->entry);
1433 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1434 subst->from.name = strdupW(english_family);
1435 subst->from.charset = -1;
1436 subst->to.name = strdupW(family_name);
1437 subst->to.charset = -1;
1438 add_font_subst(&font_subst_list, subst, 0);
1441 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1442 NULL, NULL, NULL, NULL);
1444 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1445 size = max_face_key_len + 1;
1446 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1447 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1451 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1452 load_face(hkey_face, face_name, family);
1453 RegCloseKey(hkey_face);
1454 size = max_face_key_len + 1;
1456 HeapFree(GetProcessHeap(), 0, face_name);
1457 RegCloseKey(hkey_family);
1458 size = max_family_key_len + 1;
1461 HeapFree(GetProcessHeap(), 0, family_name);
1464 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1467 HKEY hkey_wine_fonts;
1469 /* We don't want to create the fonts key as volatile, so open this first */
1470 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1471 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1472 if(ret != ERROR_SUCCESS)
1474 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1478 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1479 KEY_ALL_ACCESS, NULL, hkey, disposition);
1480 RegCloseKey(hkey_wine_fonts);
1484 static void add_face_to_cache(Face *face)
1486 HKEY hkey_font_cache, hkey_family, hkey_face;
1487 WCHAR *face_key_name;
1489 create_font_cache_key(&hkey_font_cache, NULL);
1491 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1492 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1493 if(face->family->EnglishName)
1494 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1495 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1498 face_key_name = face->StyleName;
1501 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1502 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1503 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1505 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1508 HeapFree(GetProcessHeap(), 0, face_key_name);
1510 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1512 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1513 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1515 reg_save_dword(hkey_face, face_index_value, face->face_index);
1516 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1517 reg_save_dword(hkey_face, face_version_value, face->font_version);
1518 reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1520 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1524 reg_save_dword(hkey_face, face_height_value, face->size.height);
1525 reg_save_dword(hkey_face, face_width_value, face->size.width);
1526 reg_save_dword(hkey_face, face_size_value, face->size.size);
1527 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1528 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1529 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1531 RegCloseKey(hkey_face);
1532 RegCloseKey(hkey_family);
1533 RegCloseKey(hkey_font_cache);
1536 static WCHAR *prepend_at(WCHAR *family)
1543 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1545 strcpyW(str + 1, family);
1546 HeapFree(GetProcessHeap(), 0, family);
1550 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1552 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1553 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1555 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1561 else if (!strcmpiW( *name, *english ))
1563 HeapFree( GetProcessHeap(), 0, *english );
1569 *name = prepend_at( *name );
1570 *english = prepend_at( *english );
1574 static Family *get_family( FT_Face ft_face, BOOL vertical )
1577 WCHAR *name, *english_name;
1579 get_family_names( ft_face, &name, &english_name, vertical );
1581 family = find_family_from_name( name );
1585 family = create_family( name, english_name );
1586 list_add_tail( &font_list, &family->entry );
1590 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1591 subst->from.name = strdupW( english_name );
1592 subst->from.charset = -1;
1593 subst->to.name = strdupW( name );
1594 subst->to.charset = -1;
1595 add_font_subst( &font_subst_list, subst, 0 );
1600 HeapFree( GetProcessHeap(), 0, name );
1601 HeapFree( GetProcessHeap(), 0, english_name );
1607 static inline FT_Fixed get_font_version( FT_Face ft_face )
1609 FT_Fixed version = 0;
1612 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1613 if (header) version = header->Font_Revision;
1618 static inline DWORD get_ntm_flags( FT_Face ft_face )
1621 FT_ULong table_size = 0;
1623 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1624 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1625 if (flags == 0) flags = NTM_REGULAR;
1627 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1628 flags |= NTM_PS_OPENTYPE;
1633 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1635 int internal_leading = 0;
1636 FT_WinFNT_HeaderRec winfnt_header;
1638 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1639 internal_leading = winfnt_header.internal_leading;
1641 return internal_leading;
1644 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1649 FT_WinFNT_HeaderRec winfnt_header;
1652 memset( fs, 0, sizeof(*fs) );
1654 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1657 fs->fsUsb[0] = os2->ulUnicodeRange1;
1658 fs->fsUsb[1] = os2->ulUnicodeRange2;
1659 fs->fsUsb[2] = os2->ulUnicodeRange3;
1660 fs->fsUsb[3] = os2->ulUnicodeRange4;
1662 if (os2->version == 0)
1664 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1665 fs->fsCsb[0] = FS_LATIN1;
1667 fs->fsCsb[0] = FS_SYMBOL;
1671 fs->fsCsb[0] = os2->ulCodePageRange1;
1672 fs->fsCsb[1] = os2->ulCodePageRange2;
1677 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1679 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1680 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1681 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1686 if (fs->fsCsb[0] == 0)
1688 /* let's see if we can find any interesting cmaps */
1689 for (i = 0; i < ft_face->num_charmaps; i++)
1691 switch (ft_face->charmaps[i]->encoding)
1693 case FT_ENCODING_UNICODE:
1694 case FT_ENCODING_APPLE_ROMAN:
1695 fs->fsCsb[0] |= FS_LATIN1;
1697 case FT_ENCODING_MS_SYMBOL:
1698 fs->fsCsb[0] |= FS_SYMBOL;
1707 #define ADDFONT_EXTERNAL_FONT 0x01
1708 #define ADDFONT_FORCE_BITMAP 0x02
1709 #define ADDFONT_ADD_TO_CACHE 0x04
1711 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1712 DWORD flags, BOOL vertical )
1714 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1715 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1717 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1718 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1719 if (!face->FullName)
1720 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1723 face->file = strdupA( file );
1724 face->font_data_ptr = NULL;
1725 face->font_data_size = 0;
1730 face->font_data_ptr = font_data_ptr;
1731 face->font_data_size = font_data_size;
1734 face->face_index = face_index;
1735 get_fontsig( ft_face, &face->fs );
1736 face->ntmFlags = get_ntm_flags( ft_face );
1737 face->font_version = get_font_version( ft_face );
1739 if (FT_IS_SCALABLE( ft_face ))
1741 memset( &face->size, 0, sizeof(face->size) );
1742 face->scalable = TRUE;
1746 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1747 size->height, size->width, size->size >> 6,
1748 size->x_ppem >> 6, size->y_ppem >> 6);
1749 face->size.height = size->height;
1750 face->size.width = size->width;
1751 face->size.size = size->size;
1752 face->size.x_ppem = size->x_ppem;
1753 face->size.y_ppem = size->y_ppem;
1754 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1755 face->scalable = FALSE;
1758 face->vertical = vertical;
1759 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1760 face->family = NULL;
1761 face->cached_enum_data = NULL;
1763 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1764 face->fs.fsCsb[0], face->fs.fsCsb[1],
1765 face->fs.fsUsb[0], face->fs.fsUsb[1],
1766 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1771 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1772 FT_Long face_index, DWORD flags, BOOL vertical)
1777 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1778 family = get_family( ft_face, vertical );
1779 if (!insert_face_in_family_list( face, family ))
1785 if (flags & ADDFONT_ADD_TO_CACHE)
1786 add_face_to_cache( face );
1788 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1789 debugstr_w(face->StyleName));
1792 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1793 FT_Long face_index, BOOL allow_bitmap )
1801 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1802 err = pFT_New_Face(library, file, face_index, &ft_face);
1806 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1807 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1812 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1816 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1817 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1819 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1823 if (!FT_IS_SFNT( ft_face ))
1825 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1827 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1833 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1834 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1835 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1837 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1838 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1842 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1843 we don't want to load these. */
1844 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1848 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1850 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1856 if (!ft_face->family_name || !ft_face->style_name)
1858 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1864 pFT_Done_Face( ft_face );
1868 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1871 FT_Long face_index = 0, num_faces;
1874 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1875 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1877 #ifdef HAVE_CARBON_CARBON_H
1880 char **mac_list = expand_mac_font(file);
1883 BOOL had_one = FALSE;
1885 for(cursor = mac_list; *cursor; cursor++)
1888 AddFontToList(*cursor, NULL, 0, flags);
1889 HeapFree(GetProcessHeap(), 0, *cursor);
1891 HeapFree(GetProcessHeap(), 0, mac_list);
1896 #endif /* HAVE_CARBON_CARBON_H */
1899 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1900 if (!ft_face) return 0;
1902 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1904 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1905 pFT_Done_Face(ft_face);
1909 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1912 if (FT_HAS_VERTICAL(ft_face))
1914 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1918 num_faces = ft_face->num_faces;
1919 pFT_Done_Face(ft_face);
1920 } while(num_faces > ++face_index);
1924 static void DumpFontList(void)
1928 struct list *family_elem_ptr, *face_elem_ptr;
1930 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1931 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1932 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1933 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1934 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1935 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1937 TRACE(" %d", face->size.height);
1944 /***********************************************************
1945 * The replacement list is a way to map an entire font
1946 * family onto another family. For example adding
1948 * [HKCU\Software\Wine\Fonts\Replacements]
1949 * "Wingdings"="Winedings"
1951 * would enumerate the Winedings font both as Winedings and
1952 * Wingdings. However if a real Wingdings font is present the
1953 * replacement does not take place.
1956 static void LoadReplaceList(void)
1959 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1964 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1965 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1967 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1968 &valuelen, &datalen, NULL, NULL);
1970 valuelen++; /* returned value doesn't include room for '\0' */
1971 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1972 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1976 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1977 &dlen) == ERROR_SUCCESS) {
1978 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1979 /* "NewName"="Oldname" */
1980 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1982 if(!find_family_from_any_name(value))
1984 Family * const family = find_family_from_any_name(data);
1987 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1988 if (new_family != NULL)
1990 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1991 new_family->FamilyName = strdupW(value);
1992 new_family->EnglishName = NULL;
1993 list_init(&new_family->faces);
1994 new_family->replacement = &family->faces;
1995 list_add_tail(&font_list, &new_family->entry);
2000 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2005 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2007 /* reset dlen and vlen */
2011 HeapFree(GetProcessHeap(), 0, data);
2012 HeapFree(GetProcessHeap(), 0, value);
2017 static const WCHAR *font_links_list[] =
2019 Lucida_Sans_Unicode,
2020 Microsoft_Sans_Serif,
2024 static const struct font_links_defaults_list
2026 /* Keyed off substitution for "MS Shell Dlg" */
2027 const WCHAR *shelldlg;
2028 /* Maximum of four substitutes, plus terminating NULL pointer */
2029 const WCHAR *substitutes[5];
2030 } font_links_defaults_list[] =
2032 /* Non East-Asian */
2033 { Tahoma, /* FIXME unverified ordering */
2034 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2036 /* Below lists are courtesy of
2037 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2041 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2043 /* Chinese Simplified */
2045 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2049 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2051 /* Chinese Traditional */
2053 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2058 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2060 SYSTEM_LINKS *font_link;
2062 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2064 if(!strcmpiW(font_link->font_name, name))
2071 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2083 SYSTEM_LINKS *font_link;
2085 psub = get_font_subst(&font_subst_list, name, -1);
2086 /* Don't store fonts that are only substitutes for other fonts */
2089 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2093 font_link = find_font_link(name);
2094 if (font_link == NULL)
2096 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2097 font_link->font_name = strdupW(name);
2098 list_init(&font_link->links);
2099 list_add_tail(&system_links, &font_link->entry);
2102 memset(&font_link->fs, 0, sizeof font_link->fs);
2103 for (i = 0; values[i] != NULL; i++)
2105 const struct list *face_list;
2106 CHILD_FONT *child_font;
2109 if (!strcmpiW(name,value))
2111 psub = get_font_subst(&font_subst_list, value, -1);
2113 value = psub->to.name;
2114 family = find_family_from_name(value);
2118 /* Use first extant filename for this Family */
2119 face_list = get_face_list_from_family(family);
2120 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2124 file = strrchr(face->file, '/');
2133 fileW = towstr(CP_UNIXCP, file);
2135 face = find_face_from_filename(fileW, value);
2138 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2142 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2143 child_font->face = face;
2144 child_font->font = NULL;
2145 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2146 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2147 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2148 list_add_tail(&font_link->links, &child_font->entry);
2150 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2151 HeapFree(GetProcessHeap(), 0, fileW);
2157 /*************************************************************
2160 static BOOL init_system_links(void)
2164 DWORD type, max_val, max_data, val_len, data_len, index;
2165 WCHAR *value, *data;
2166 WCHAR *entry, *next;
2167 SYSTEM_LINKS *font_link, *system_font_link;
2168 CHILD_FONT *child_font;
2169 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2170 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2171 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2176 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2178 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2179 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2180 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2181 val_len = max_val + 1;
2182 data_len = max_data;
2184 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2186 psub = get_font_subst(&font_subst_list, value, -1);
2187 /* Don't store fonts that are only substitutes for other fonts */
2190 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2193 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2194 font_link->font_name = strdupW(value);
2195 memset(&font_link->fs, 0, sizeof font_link->fs);
2196 list_init(&font_link->links);
2197 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2200 CHILD_FONT *child_font;
2202 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2204 next = entry + strlenW(entry) + 1;
2206 face_name = strchrW(entry, ',');
2210 while(isspaceW(*face_name))
2213 psub = get_font_subst(&font_subst_list, face_name, -1);
2215 face_name = psub->to.name;
2217 face = find_face_from_filename(entry, face_name);
2220 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2224 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2225 child_font->face = face;
2226 child_font->font = NULL;
2227 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2228 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2229 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2230 list_add_tail(&font_link->links, &child_font->entry);
2232 list_add_tail(&system_links, &font_link->entry);
2234 val_len = max_val + 1;
2235 data_len = max_data;
2238 HeapFree(GetProcessHeap(), 0, value);
2239 HeapFree(GetProcessHeap(), 0, data);
2244 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2246 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2250 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2252 const FontSubst *psub2;
2253 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2255 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2257 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2258 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2260 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2261 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2263 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2265 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2271 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2274 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2275 system_font_link->font_name = strdupW(System);
2276 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2277 list_init(&system_font_link->links);
2279 face = find_face_from_filename(tahoma_ttf, Tahoma);
2282 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2283 child_font->face = face;
2284 child_font->font = NULL;
2285 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2286 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2287 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2288 list_add_tail(&system_font_link->links, &child_font->entry);
2290 font_link = find_font_link(Tahoma);
2291 if (font_link != NULL)
2293 CHILD_FONT *font_link_entry;
2294 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2296 CHILD_FONT *new_child;
2297 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2298 new_child->face = font_link_entry->face;
2299 new_child->font = NULL;
2300 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2301 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2302 list_add_tail(&system_font_link->links, &new_child->entry);
2305 list_add_tail(&system_links, &system_font_link->entry);
2309 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2312 struct dirent *dent;
2313 char path[MAX_PATH];
2315 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2317 dir = opendir(dirname);
2319 WARN("Can't open directory %s\n", debugstr_a(dirname));
2322 while((dent = readdir(dir)) != NULL) {
2323 struct stat statbuf;
2325 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2328 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2330 sprintf(path, "%s/%s", dirname, dent->d_name);
2332 if(stat(path, &statbuf) == -1)
2334 WARN("Can't stat %s\n", debugstr_a(path));
2337 if(S_ISDIR(statbuf.st_mode))
2338 ReadFontDir(path, external_fonts);
2341 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2342 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2343 AddFontToList(path, NULL, 0, addfont_flags);
2350 #ifdef SONAME_LIBFONTCONFIG
2351 static void load_fontconfig_fonts(void)
2353 void *fc_handle = NULL;
2362 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2364 TRACE("Wine cannot find the fontconfig library (%s).\n",
2365 SONAME_LIBFONTCONFIG);
2368 #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;}
2369 LOAD_FUNCPTR(FcConfigGetCurrent);
2370 LOAD_FUNCPTR(FcFontList);
2371 LOAD_FUNCPTR(FcFontSetDestroy);
2372 LOAD_FUNCPTR(FcInit);
2373 LOAD_FUNCPTR(FcObjectSetAdd);
2374 LOAD_FUNCPTR(FcObjectSetCreate);
2375 LOAD_FUNCPTR(FcObjectSetDestroy);
2376 LOAD_FUNCPTR(FcPatternCreate);
2377 LOAD_FUNCPTR(FcPatternDestroy);
2378 LOAD_FUNCPTR(FcPatternGetBool);
2379 LOAD_FUNCPTR(FcPatternGetString);
2382 if(!pFcInit()) return;
2384 config = pFcConfigGetCurrent();
2385 pat = pFcPatternCreate();
2386 os = pFcObjectSetCreate();
2387 pFcObjectSetAdd(os, FC_FILE);
2388 pFcObjectSetAdd(os, FC_SCALABLE);
2389 fontset = pFcFontList(config, pat, os);
2390 if(!fontset) return;
2391 for(i = 0; i < fontset->nfont; i++) {
2394 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2396 TRACE("fontconfig: %s\n", file);
2398 /* We're just interested in OT/TT fonts for now, so this hack just
2399 picks up the scalable fonts without extensions .pf[ab] to save time
2400 loading every other font */
2402 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2404 TRACE("not scalable\n");
2408 len = strlen( file );
2409 if(len < 4) continue;
2410 ext = &file[ len - 3 ];
2411 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2412 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2414 pFcFontSetDestroy(fontset);
2415 pFcObjectSetDestroy(os);
2416 pFcPatternDestroy(pat);
2421 #elif defined(HAVE_CARBON_CARBON_H)
2423 static void load_mac_font_callback(const void *value, void *context)
2425 CFStringRef pathStr = value;
2429 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2430 path = HeapAlloc(GetProcessHeap(), 0, len);
2431 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2433 TRACE("font file %s\n", path);
2434 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2436 HeapFree(GetProcessHeap(), 0, path);
2439 static void load_mac_fonts(void)
2441 CFStringRef removeDupesKey;
2442 CFBooleanRef removeDupesValue;
2443 CFDictionaryRef options;
2444 CTFontCollectionRef col;
2446 CFMutableSetRef paths;
2449 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2450 removeDupesValue = kCFBooleanTrue;
2451 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2452 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2453 col = CTFontCollectionCreateFromAvailableFonts(options);
2454 if (options) CFRelease(options);
2457 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2461 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2465 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2469 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2472 WARN("CFSetCreateMutable failed\n");
2477 for (i = 0; i < CFArrayGetCount(descs); i++)
2479 CTFontDescriptorRef desc;
2488 desc = CFArrayGetValueAtIndex(descs, i);
2490 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2491 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2492 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2493 if (!font) continue;
2495 atsFont = CTFontGetPlatformFont(font, NULL);
2502 status = ATSFontGetFileReference(atsFont, &fsref);
2504 if (status != noErr) continue;
2506 url = CFURLCreateFromFSRef(NULL, &fsref);
2509 ext = CFURLCopyPathExtension(url);
2512 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2513 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2522 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2524 if (!path) continue;
2526 CFSetAddValue(paths, path);
2532 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2538 static BOOL load_font_from_data_dir(LPCWSTR file)
2541 const char *data_dir = wine_get_data_dir();
2543 if (!data_dir) data_dir = wine_get_build_dir();
2550 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2552 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2554 strcpy(unix_name, data_dir);
2555 strcat(unix_name, "/fonts/");
2557 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2559 EnterCriticalSection( &freetype_cs );
2560 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2561 LeaveCriticalSection( &freetype_cs );
2562 HeapFree(GetProcessHeap(), 0, unix_name);
2567 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2569 static const WCHAR slashW[] = {'\\','\0'};
2571 WCHAR windowsdir[MAX_PATH];
2574 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2575 strcatW(windowsdir, fontsW);
2576 strcatW(windowsdir, slashW);
2577 strcatW(windowsdir, file);
2578 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2579 EnterCriticalSection( &freetype_cs );
2580 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2581 LeaveCriticalSection( &freetype_cs );
2582 HeapFree(GetProcessHeap(), 0, unixname);
2587 static void load_system_fonts(void)
2590 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2591 const WCHAR * const *value;
2593 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2596 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2597 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2598 strcatW(windowsdir, fontsW);
2599 for(value = SystemFontValues; *value; value++) {
2600 dlen = sizeof(data);
2601 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2605 sprintfW(pathW, fmtW, windowsdir, data);
2606 if((unixname = wine_get_unix_file_name(pathW))) {
2607 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2608 HeapFree(GetProcessHeap(), 0, unixname);
2611 load_font_from_data_dir(data);
2618 /*************************************************************
2620 * This adds registry entries for any externally loaded fonts
2621 * (fonts from fontconfig or FontDirs). It also deletes entries
2622 * of no longer existing fonts.
2625 static void update_reg_entries(void)
2627 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2632 struct list *family_elem_ptr, *face_elem_ptr;
2634 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2637 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2638 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2639 ERR("Can't create Windows font reg key\n");
2643 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2644 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2645 ERR("Can't create Windows font reg key\n");
2649 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2650 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2651 ERR("Can't create external font reg key\n");
2655 /* enumerate the fonts and add external ones to the two keys */
2657 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2658 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2659 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2660 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2661 if(!face->external) continue;
2665 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2666 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2667 strcpyW(valueW, face->FullName);
2671 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2672 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2673 strcpyW(valueW, family->FamilyName);
2676 file = wine_get_dos_file_name(face->file);
2678 len = strlenW(file) + 1;
2681 if((path = strrchr(face->file, '/')) == NULL)
2685 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2687 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2688 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2690 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2691 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2692 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2694 HeapFree(GetProcessHeap(), 0, file);
2695 HeapFree(GetProcessHeap(), 0, valueW);
2699 if(external_key) RegCloseKey(external_key);
2700 if(win9x_key) RegCloseKey(win9x_key);
2701 if(winnt_key) RegCloseKey(winnt_key);
2705 static void delete_external_font_keys(void)
2707 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2708 DWORD dlen, vlen, datalen, valuelen, i, type;
2712 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2713 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2714 ERR("Can't create Windows font reg key\n");
2718 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2719 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2720 ERR("Can't create Windows font reg key\n");
2724 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2725 ERR("Can't create external font reg key\n");
2729 /* Delete all external fonts added last time */
2731 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2732 &valuelen, &datalen, NULL, NULL);
2733 valuelen++; /* returned value doesn't include room for '\0' */
2734 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2735 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2737 dlen = datalen * sizeof(WCHAR);
2740 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2741 &dlen) == ERROR_SUCCESS) {
2743 RegDeleteValueW(winnt_key, valueW);
2744 RegDeleteValueW(win9x_key, valueW);
2745 /* reset dlen and vlen */
2749 HeapFree(GetProcessHeap(), 0, data);
2750 HeapFree(GetProcessHeap(), 0, valueW);
2752 /* Delete the old external fonts key */
2753 RegCloseKey(external_key);
2754 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2757 if(win9x_key) RegCloseKey(win9x_key);
2758 if(winnt_key) RegCloseKey(winnt_key);
2761 /*************************************************************
2762 * WineEngAddFontResourceEx
2765 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2771 if (ft_handle) /* do it only if we have freetype up and running */
2776 FIXME("Ignoring flags %x\n", flags);
2778 if((unixname = wine_get_unix_file_name(file)))
2780 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2782 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2783 EnterCriticalSection( &freetype_cs );
2784 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2785 LeaveCriticalSection( &freetype_cs );
2786 HeapFree(GetProcessHeap(), 0, unixname);
2788 if (!ret && !strchrW(file, '\\')) {
2789 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2790 ret = load_font_from_winfonts_dir(file);
2792 /* Try in datadir/fonts (or builddir/fonts),
2793 * needed for Magic the Gathering Online
2795 ret = load_font_from_data_dir(file);
2802 /*************************************************************
2803 * WineEngAddFontMemResourceEx
2806 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2810 if (ft_handle) /* do it only if we have freetype up and running */
2812 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2814 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2815 memcpy(pFontCopy, pbFont, cbFont);
2817 EnterCriticalSection( &freetype_cs );
2818 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2819 LeaveCriticalSection( &freetype_cs );
2823 TRACE("AddFontToList failed\n");
2824 HeapFree(GetProcessHeap(), 0, pFontCopy);
2827 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2828 * For now return something unique but quite random
2830 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2831 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2838 /*************************************************************
2839 * WineEngRemoveFontResourceEx
2842 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2845 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2849 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2855 if (!font_file) return NULL;
2857 file_len = strlenW( font_file );
2859 if (font_path && font_path[0])
2861 int path_len = strlenW( font_path );
2862 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2863 if (!fullname) return NULL;
2864 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2865 fullname[path_len] = '\\';
2866 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2870 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2871 if (!len) return NULL;
2872 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2873 if (!fullname) return NULL;
2874 GetFullPathNameW( font_file, len, fullname, NULL );
2877 unix_name = wine_get_unix_file_name( fullname );
2878 HeapFree( GetProcessHeap(), 0, fullname );
2882 #include <pshpack1.h>
2885 WORD num_of_resources;
2889 CHAR dfCopyright[60];
2895 WORD dfInternalLeading;
2896 WORD dfExternalLeading;
2904 BYTE dfPitchAndFamily;
2915 CHAR szFaceName[LF_FACESIZE];
2918 #include <poppack.h>
2920 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2921 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2923 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2925 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2928 WCHAR *name, *english_name;
2930 NEWTEXTMETRICEXW ntm;
2933 if (!ft_face) return FALSE;
2934 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE );
2935 get_family_names( ft_face, &name, &english_name, FALSE );
2936 family = create_family( name, english_name );
2937 insert_face_in_family_list( face, family );
2938 pFT_Done_Face( ft_face );
2940 GetEnumStructs( face, &elf, &ntm, &type );
2941 free_family( family );
2943 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
2945 memset( fd, 0, sizeof(*fd) );
2947 fd->num_of_resources = 1;
2949 fd->dfVersion = 0x200;
2950 fd->dfSize = sizeof(*fd);
2951 strcpy( fd->dfCopyright, "Wine fontdir" );
2952 fd->dfType = 0x4003; /* 0x0080 set if private */
2953 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
2955 fd->dfHorizRes = 72;
2956 fd->dfAscent = ntm.ntmTm.tmAscent;
2957 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
2958 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
2959 fd->dfItalic = ntm.ntmTm.tmItalic;
2960 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
2961 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
2962 fd->dfWeight = ntm.ntmTm.tmWeight;
2963 fd->dfCharSet = ntm.ntmTm.tmCharSet;
2965 fd->dfPixHeight = ntm.ntmTm.tmHeight;
2966 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
2967 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
2968 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
2969 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
2970 fd->dfLastChar = ntm.ntmTm.tmLastChar;
2971 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
2972 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
2973 fd->dfWidthBytes = 0;
2975 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
2977 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
2982 #define NE_FFLAGS_LIBMODULE 0x8000
2983 #define NE_OSFLAGS_WINDOWS 0x02
2985 static const char dos_string[0x40] = "This is a TrueType resource file";
2986 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
2988 #include <pshpack2.h>
3009 struct ne_typeinfo fontdir_type;
3010 struct ne_nameinfo fontdir_name;
3011 struct ne_typeinfo scalable_type;
3012 struct ne_nameinfo scalable_name;
3014 BYTE fontdir_res_name[8];
3017 #include <poppack.h>
3019 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3023 DWORD size, written;
3025 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3026 char *font_fileA, *last_part, *ext;
3027 IMAGE_DOS_HEADER dos;
3028 IMAGE_OS2_HEADER ne =
3030 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3032 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3033 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3035 struct rsrc_tab rsrc_tab =
3039 { 0, 0, 0x0c50, 0x2c, 0 },
3041 { 0, 0, 0x0c50, 0x8001, 0 },
3043 { 7,'F','O','N','T','D','I','R'}
3046 memset( &dos, 0, sizeof(dos) );
3047 dos.e_magic = IMAGE_DOS_SIGNATURE;
3048 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3050 /* import name is last part\0, resident name is last part without extension
3051 non-resident name is "FONTRES:" + lfFaceName */
3053 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3054 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3055 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3057 last_part = strrchr( font_fileA, '\\' );
3058 if (last_part) last_part++;
3059 else last_part = font_fileA;
3060 import_name_len = strlen( last_part ) + 1;
3062 ext = strchr( last_part, '.' );
3063 if (ext) res_name_len = ext - last_part;
3064 else res_name_len = import_name_len - 1;
3066 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3068 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3069 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3070 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3071 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3073 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3075 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3076 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3077 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3078 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3080 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3081 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3085 HeapFree( GetProcessHeap(), 0, font_fileA );
3089 memcpy( ptr, &dos, sizeof(dos) );
3090 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3091 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3093 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3094 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3096 ptr = start + dos.e_lfanew + ne.ne_restab;
3097 *ptr++ = res_name_len;
3098 memcpy( ptr, last_part, res_name_len );
3100 ptr = start + dos.e_lfanew + ne.ne_imptab;
3101 *ptr++ = import_name_len;
3102 memcpy( ptr, last_part, import_name_len );
3104 ptr = start + ne.ne_nrestab;
3105 *ptr++ = non_res_name_len;
3106 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3107 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3109 ptr = start + (rsrc_tab.scalable_name.off << 4);
3110 memcpy( ptr, font_fileA, font_file_len );
3112 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3113 memcpy( ptr, fontdir, fontdir->dfSize );
3115 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3116 if (file != INVALID_HANDLE_VALUE)
3118 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3120 CloseHandle( file );
3123 HeapFree( GetProcessHeap(), 0, start );
3124 HeapFree( GetProcessHeap(), 0, font_fileA );
3129 /*************************************************************
3130 * WineEngCreateScalableFontResource
3133 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3134 LPCWSTR font_file, LPCWSTR font_path )
3136 char *unix_name = get_ttf_file_name( font_file, font_path );
3137 struct fontdir fontdir;
3140 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3141 SetLastError( ERROR_INVALID_PARAMETER );
3144 if (hidden) fontdir.dfType |= 0x80;
3145 ret = create_fot( resource, font_file, &fontdir );
3148 HeapFree( GetProcessHeap(), 0, unix_name );
3152 static const struct nls_update_font_list
3154 UINT ansi_cp, oem_cp;
3155 const char *oem, *fixed, *system;
3156 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3157 /* these are for font substitutes */
3158 const char *shelldlg, *tmsrmn;
3159 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3163 const char *from, *to;
3164 } arial_0, courier_new_0, times_new_roman_0;
3165 } nls_update_font_list[] =
3167 /* Latin 1 (United States) */
3168 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3169 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3170 "Tahoma","Times New Roman",
3171 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3174 /* Latin 1 (Multilingual) */
3175 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3176 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3177 "Tahoma","Times New Roman", /* FIXME unverified */
3178 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3181 /* Eastern Europe */
3182 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3183 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3184 "Tahoma","Times New Roman", /* FIXME unverified */
3185 "Fixedsys,238", "System,238",
3186 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3187 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3188 { "Arial CE,0", "Arial,238" },
3189 { "Courier New CE,0", "Courier New,238" },
3190 { "Times New Roman CE,0", "Times New Roman,238" }
3193 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3194 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3195 "Tahoma","Times New Roman", /* FIXME unverified */
3196 "Fixedsys,204", "System,204",
3197 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3198 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3199 { "Arial Cyr,0", "Arial,204" },
3200 { "Courier New Cyr,0", "Courier New,204" },
3201 { "Times New Roman Cyr,0", "Times New Roman,204" }
3204 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3205 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3206 "Tahoma","Times New Roman", /* FIXME unverified */
3207 "Fixedsys,161", "System,161",
3208 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3209 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3210 { "Arial Greek,0", "Arial,161" },
3211 { "Courier New Greek,0", "Courier New,161" },
3212 { "Times New Roman Greek,0", "Times New Roman,161" }
3215 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3216 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3217 "Tahoma","Times New Roman", /* FIXME unverified */
3218 "Fixedsys,162", "System,162",
3219 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3220 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3221 { "Arial Tur,0", "Arial,162" },
3222 { "Courier New Tur,0", "Courier New,162" },
3223 { "Times New Roman Tur,0", "Times New Roman,162" }
3226 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3227 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3228 "Tahoma","Times New Roman", /* FIXME unverified */
3229 "Fixedsys,177", "System,177",
3230 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3231 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3235 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3236 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3237 "Tahoma","Times New Roman", /* FIXME unverified */
3238 "Fixedsys,178", "System,178",
3239 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3240 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3244 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3245 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3246 "Tahoma","Times New Roman", /* FIXME unverified */
3247 "Fixedsys,186", "System,186",
3248 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3249 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3250 { "Arial Baltic,0", "Arial,186" },
3251 { "Courier New Baltic,0", "Courier New,186" },
3252 { "Times New Roman Baltic,0", "Times New Roman,186" }
3255 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3256 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3257 "Tahoma","Times New Roman", /* FIXME unverified */
3258 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3262 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3263 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3264 "Tahoma","Times New Roman", /* FIXME unverified */
3265 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3269 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3270 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3271 "MS UI Gothic","MS Serif",
3272 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3275 /* Chinese Simplified */
3276 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3277 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3278 "SimSun", "NSimSun",
3279 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3283 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3284 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3286 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3289 /* Chinese Traditional */
3290 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3291 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3292 "PMingLiU", "MingLiU",
3293 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3298 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3300 return ( ansi_cp == 932 /* CP932 for Japanese */
3301 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3302 || ansi_cp == 949 /* CP949 for Korean */
3303 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3306 static inline HKEY create_fonts_NT_registry_key(void)
3310 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3311 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3315 static inline HKEY create_fonts_9x_registry_key(void)
3319 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3320 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3324 static inline HKEY create_config_fonts_registry_key(void)
3328 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3329 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3333 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3335 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3337 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3338 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3339 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3340 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3343 static void set_value_key(HKEY hkey, const char *name, const char *value)
3346 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3348 RegDeleteValueA(hkey, name);
3351 static void update_font_info(void)
3353 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3354 char buf[40], cpbuf[40];
3357 UINT i, ansi_cp = 0, oem_cp = 0;
3358 DWORD screen_dpi = 96, font_dpi = 0;
3361 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3362 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3363 &hkey) == ERROR_SUCCESS)
3365 reg_load_dword(hkey, logpixels, &screen_dpi);
3369 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3372 reg_load_dword(hkey, logpixels, &font_dpi);
3374 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3375 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3376 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3377 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3378 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3380 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3381 if (is_dbcs_ansi_cp(ansi_cp))
3382 use_default_fallback = TRUE;
3385 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3387 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3392 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3393 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3395 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3396 ansi_cp, oem_cp, screen_dpi);
3398 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3399 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3402 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3406 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3407 nls_update_font_list[i].oem_cp == oem_cp)
3409 hkey = create_config_fonts_registry_key();
3410 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3411 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3412 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3415 hkey = create_fonts_NT_registry_key();
3416 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3419 hkey = create_fonts_9x_registry_key();
3420 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3423 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3425 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3426 strlen(nls_update_font_list[i].shelldlg)+1);
3427 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3428 strlen(nls_update_font_list[i].tmsrmn)+1);
3430 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3431 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3432 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3433 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3434 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3435 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3436 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3437 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3439 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3440 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3441 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3449 /* Delete the FontSubstitutes from other locales */
3450 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3452 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3453 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3454 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3460 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3463 static BOOL init_freetype(void)
3465 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3468 "Wine cannot find the FreeType font library. To enable Wine to\n"
3469 "use TrueType fonts please install a version of FreeType greater than\n"
3470 "or equal to 2.0.5.\n"
3471 "http://www.freetype.org\n");
3475 #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;}
3477 LOAD_FUNCPTR(FT_Done_Face)
3478 LOAD_FUNCPTR(FT_Get_Char_Index)
3479 LOAD_FUNCPTR(FT_Get_First_Char)
3480 LOAD_FUNCPTR(FT_Get_Module)
3481 LOAD_FUNCPTR(FT_Get_Next_Char)
3482 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3483 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3484 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3485 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3486 LOAD_FUNCPTR(FT_Init_FreeType)
3487 LOAD_FUNCPTR(FT_Library_Version)
3488 LOAD_FUNCPTR(FT_Load_Glyph)
3489 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3490 LOAD_FUNCPTR(FT_Matrix_Multiply)
3491 #ifndef FT_MULFIX_INLINED
3492 LOAD_FUNCPTR(FT_MulFix)
3494 LOAD_FUNCPTR(FT_New_Face)
3495 LOAD_FUNCPTR(FT_New_Memory_Face)
3496 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3497 LOAD_FUNCPTR(FT_Outline_Transform)
3498 LOAD_FUNCPTR(FT_Outline_Translate)
3499 LOAD_FUNCPTR(FT_Render_Glyph)
3500 LOAD_FUNCPTR(FT_Select_Charmap)
3501 LOAD_FUNCPTR(FT_Set_Charmap)
3502 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3503 LOAD_FUNCPTR(FT_Vector_Transform)
3504 LOAD_FUNCPTR(FT_Vector_Unit)
3506 /* Don't warn if these ones are missing */
3507 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3508 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3509 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3512 if(pFT_Init_FreeType(&library) != 0) {
3513 ERR("Can't init FreeType library\n");
3514 wine_dlclose(ft_handle, NULL, 0);
3518 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3520 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3521 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3522 ((FT_Version.minor << 8) & 0x00ff00) |
3523 ((FT_Version.patch ) & 0x0000ff);
3525 font_driver = &freetype_funcs;
3530 "Wine cannot find certain functions that it needs inside the FreeType\n"
3531 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3532 "FreeType to at least version 2.1.4.\n"
3533 "http://www.freetype.org\n");
3534 wine_dlclose(ft_handle, NULL, 0);
3539 static void init_font_list(void)
3541 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3542 static const WCHAR pathW[] = {'P','a','t','h',0};
3544 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3545 WCHAR windowsdir[MAX_PATH];
3547 const char *data_dir;
3549 delete_external_font_keys();
3551 /* load the system bitmap fonts */
3552 load_system_fonts();
3554 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3555 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3556 strcatW(windowsdir, fontsW);
3557 if((unixname = wine_get_unix_file_name(windowsdir)))
3559 ReadFontDir(unixname, FALSE);
3560 HeapFree(GetProcessHeap(), 0, unixname);
3563 /* load the system truetype fonts */
3564 data_dir = wine_get_data_dir();
3565 if (!data_dir) data_dir = wine_get_build_dir();
3566 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3568 strcpy(unixname, data_dir);
3569 strcat(unixname, "/fonts/");
3570 ReadFontDir(unixname, TRUE);
3571 HeapFree(GetProcessHeap(), 0, unixname);
3574 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3575 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3576 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3578 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3579 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3580 &hkey) == ERROR_SUCCESS)
3582 LPWSTR data, valueW;
3583 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3584 &valuelen, &datalen, NULL, NULL);
3586 valuelen++; /* returned value doesn't include room for '\0' */
3587 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3588 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3591 dlen = datalen * sizeof(WCHAR);
3593 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3594 &dlen) == ERROR_SUCCESS)
3596 if(data[0] && (data[1] == ':'))
3598 if((unixname = wine_get_unix_file_name(data)))
3600 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3601 HeapFree(GetProcessHeap(), 0, unixname);
3604 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3606 WCHAR pathW[MAX_PATH];
3607 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3610 sprintfW(pathW, fmtW, windowsdir, data);
3611 if((unixname = wine_get_unix_file_name(pathW)))
3613 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3614 HeapFree(GetProcessHeap(), 0, unixname);
3617 load_font_from_data_dir(data);
3619 /* reset dlen and vlen */
3624 HeapFree(GetProcessHeap(), 0, data);
3625 HeapFree(GetProcessHeap(), 0, valueW);
3629 #ifdef SONAME_LIBFONTCONFIG
3630 load_fontconfig_fonts();
3631 #elif defined(HAVE_CARBON_CARBON_H)
3635 /* then look in any directories that we've specified in the config file */
3636 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3637 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3643 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3645 len += sizeof(WCHAR);
3646 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3647 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3649 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3650 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3651 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3652 TRACE( "got font path %s\n", debugstr_a(valueA) );
3657 LPSTR next = strchr( ptr, ':' );
3658 if (next) *next++ = 0;
3659 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3660 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3662 strcpy( unixname, home );
3663 strcat( unixname, ptr + 1 );
3664 ReadFontDir( unixname, TRUE );
3665 HeapFree( GetProcessHeap(), 0, unixname );
3668 ReadFontDir( ptr, TRUE );
3671 HeapFree( GetProcessHeap(), 0, valueA );
3673 HeapFree( GetProcessHeap(), 0, valueW );
3679 static BOOL move_to_front(const WCHAR *name)
3681 Family *family, *cursor2;
3682 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3684 if(!strcmpiW(family->FamilyName, name))
3686 list_remove(&family->entry);
3687 list_add_head(&font_list, &family->entry);
3694 static BOOL set_default(const WCHAR **name_list)
3698 if (move_to_front(*name_list)) return TRUE;
3705 static void reorder_font_list(void)
3707 set_default( default_serif_list );
3708 set_default( default_fixed_list );
3709 set_default( default_sans_list );
3712 /*************************************************************
3715 * Initialize FreeType library and create a list of available faces
3717 BOOL WineEngInit(void)
3719 HKEY hkey_font_cache;
3723 /* update locale dependent font info in registry */
3726 if(!init_freetype()) return FALSE;
3728 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3730 ERR("Failed to create font mutex\n");
3733 WaitForSingleObject(font_mutex, INFINITE);
3735 create_font_cache_key(&hkey_font_cache, &disposition);
3737 if(disposition == REG_CREATED_NEW_KEY)
3740 load_font_list_from_cache(hkey_font_cache);
3742 RegCloseKey(hkey_font_cache);
3744 reorder_font_list();
3751 if(disposition == REG_CREATED_NEW_KEY)
3752 update_reg_entries();
3754 init_system_links();
3756 ReleaseMutex(font_mutex);
3761 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3764 TT_HoriHeader *pHori;
3768 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3769 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3771 if(height == 0) height = 16;
3773 /* Calc. height of EM square:
3775 * For +ve lfHeight we have
3776 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3777 * Re-arranging gives:
3778 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3780 * For -ve lfHeight we have
3782 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3783 * with il = winAscent + winDescent - units_per_em]
3788 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3789 ppem = MulDiv(ft_face->units_per_EM, height,
3790 pHori->Ascender - pHori->Descender);
3792 ppem = MulDiv(ft_face->units_per_EM, height,
3793 pOS2->usWinAscent + pOS2->usWinDescent);
3801 static struct font_mapping *map_font_file( const char *name )
3803 struct font_mapping *mapping;
3807 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3808 if (fstat( fd, &st ) == -1) goto error;
3810 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3812 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3814 mapping->refcount++;
3819 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3822 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3825 if (mapping->data == MAP_FAILED)
3827 HeapFree( GetProcessHeap(), 0, mapping );
3830 mapping->refcount = 1;
3831 mapping->dev = st.st_dev;
3832 mapping->ino = st.st_ino;
3833 mapping->size = st.st_size;
3834 list_add_tail( &mappings_list, &mapping->entry );
3842 static void unmap_font_file( struct font_mapping *mapping )
3844 if (!--mapping->refcount)
3846 list_remove( &mapping->entry );
3847 munmap( mapping->data, mapping->size );
3848 HeapFree( GetProcessHeap(), 0, mapping );
3852 static LONG load_VDMX(GdiFont*, LONG);
3854 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3861 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3865 if (!(font->mapping = map_font_file( face->file )))
3867 WARN("failed to map %s\n", debugstr_a(face->file));
3870 data_ptr = font->mapping->data;
3871 data_size = font->mapping->size;
3875 data_ptr = face->font_data_ptr;
3876 data_size = face->font_data_size;
3879 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3881 ERR("FT_New_Face rets %d\n", err);
3885 /* set it here, as load_VDMX needs it */
3886 font->ft_face = ft_face;
3888 if(FT_IS_SCALABLE(ft_face)) {
3889 /* load the VDMX table if we have one */
3890 font->ppem = load_VDMX(font, height);
3892 font->ppem = calc_ppem_for_height(ft_face, height);
3893 TRACE("height %d => ppem %d\n", height, font->ppem);
3895 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3896 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3898 font->ppem = height;
3899 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3900 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3906 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3908 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3909 a single face with the requested charset. The idea is to check if
3910 the selected font supports the current ANSI codepage, if it does
3911 return the corresponding charset, else return the first charset */
3914 int acp = GetACP(), i;
3918 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3920 const SYSTEM_LINKS *font_link;
3922 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3923 return csi.ciCharset;
3925 font_link = find_font_link(family_name);
3926 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3927 return csi.ciCharset;
3930 for(i = 0; i < 32; i++) {
3932 if(face->fs.fsCsb[0] & fs0) {
3933 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3935 return csi.ciCharset;
3938 FIXME("TCI failing on %x\n", fs0);
3942 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3943 face->fs.fsCsb[0], face->file);
3945 return DEFAULT_CHARSET;
3948 static GdiFont *alloc_font(void)
3950 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3952 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3953 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3955 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3956 ret->total_kern_pairs = (DWORD)-1;
3957 ret->kern_pairs = NULL;
3958 list_init(&ret->hfontlist);
3959 list_init(&ret->child_fonts);
3963 static void free_font(GdiFont *font)
3965 struct list *cursor, *cursor2;
3968 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3970 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3971 list_remove(cursor);
3973 free_font(child->font);
3974 HeapFree(GetProcessHeap(), 0, child);
3977 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3979 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3980 DeleteObject(hfontlist->hfont);
3981 list_remove(&hfontlist->entry);
3982 HeapFree(GetProcessHeap(), 0, hfontlist);
3985 if (font->ft_face) pFT_Done_Face(font->ft_face);
3986 if (font->mapping) unmap_font_file( font->mapping );
3987 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3988 HeapFree(GetProcessHeap(), 0, font->potm);
3989 HeapFree(GetProcessHeap(), 0, font->name);
3990 for (i = 0; i < font->gmsize; i++)
3991 HeapFree(GetProcessHeap(),0,font->gm[i]);
3992 HeapFree(GetProcessHeap(), 0, font->gm);
3993 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3994 HeapFree(GetProcessHeap(), 0, font);
3998 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4000 FT_Face ft_face = font->ft_face;
4004 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4011 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4013 /* make sure value of len is the value freetype says it needs */
4016 FT_ULong needed = 0;
4017 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4018 if( !err && needed < len) len = needed;
4020 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4023 TRACE("Can't find table %c%c%c%c\n",
4024 /* bytes were reversed */
4025 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4026 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4032 /*************************************************************
4035 * load the vdmx entry for the specified height
4038 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4039 ( ( (FT_ULong)_x4 << 24 ) | \
4040 ( (FT_ULong)_x3 << 16 ) | \
4041 ( (FT_ULong)_x2 << 8 ) | \
4044 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4059 static LONG load_VDMX(GdiFont *font, LONG height)
4063 BYTE devXRatio, devYRatio;
4064 USHORT numRecs, numRatios;
4065 DWORD result, offset = -1;
4069 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4071 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4074 /* FIXME: need the real device aspect ratio */
4078 numRecs = GET_BE_WORD(hdr[1]);
4079 numRatios = GET_BE_WORD(hdr[2]);
4081 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4082 for(i = 0; i < numRatios; i++) {
4085 offset = (3 * 2) + (i * sizeof(Ratios));
4086 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4089 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4091 if((ratio.xRatio == 0 &&
4092 ratio.yStartRatio == 0 &&
4093 ratio.yEndRatio == 0) ||
4094 (devXRatio == ratio.xRatio &&
4095 devYRatio >= ratio.yStartRatio &&
4096 devYRatio <= ratio.yEndRatio))
4098 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4099 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4100 offset = GET_BE_WORD(tmp);
4106 FIXME("No suitable ratio found\n");
4110 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4112 BYTE startsz, endsz;
4115 recs = GET_BE_WORD(group.recs);
4116 startsz = group.startsz;
4117 endsz = group.endsz;
4119 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4121 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4122 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4123 if(result == GDI_ERROR) {
4124 FIXME("Failed to retrieve vTable\n");
4129 for(i = 0; i < recs; i++) {
4130 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4131 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4132 ppem = GET_BE_WORD(vTable[i * 3]);
4134 if(yMax + -yMin == height) {
4137 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4140 if(yMax + -yMin > height) {
4143 goto end; /* failed */
4145 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4146 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4147 ppem = GET_BE_WORD(vTable[i * 3]);
4148 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4154 TRACE("ppem not found for height %d\n", height);
4158 HeapFree(GetProcessHeap(), 0, vTable);
4164 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4166 if(font->font_desc.hash != fd->hash) return TRUE;
4167 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4168 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4169 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4170 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4173 static void calc_hash(FONT_DESC *pfd)
4175 DWORD hash = 0, *ptr, two_chars;
4179 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4181 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4183 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4185 pwc = (WCHAR *)&two_chars;
4187 *pwc = toupperW(*pwc);
4189 *pwc = toupperW(*pwc);
4193 hash ^= !pfd->can_use_bitmap;
4198 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4203 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4207 fd.can_use_bitmap = can_use_bitmap;
4210 /* try the child list */
4211 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4212 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4213 if(!fontcmp(ret, &fd)) {
4214 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4215 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4216 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4217 if(hflist->hfont == hfont)
4223 /* try the in-use list */
4224 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4225 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4226 if(!fontcmp(ret, &fd)) {
4227 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4228 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4229 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4230 if(hflist->hfont == hfont)
4233 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4234 hflist->hfont = hfont;
4235 list_add_head(&ret->hfontlist, &hflist->entry);
4240 /* then the unused list */
4241 font_elem_ptr = list_head(&unused_gdi_font_list);
4242 while(font_elem_ptr) {
4243 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4244 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4245 if(!fontcmp(ret, &fd)) {
4246 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4247 assert(list_empty(&ret->hfontlist));
4248 TRACE("Found %p in unused list\n", ret);
4249 list_remove(&ret->entry);
4250 list_add_head(&gdi_font_list, &ret->entry);
4251 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4252 hflist->hfont = hfont;
4253 list_add_head(&ret->hfontlist, &hflist->entry);
4260 static void add_to_cache(GdiFont *font)
4262 static DWORD cache_num = 1;
4264 font->cache_num = cache_num++;
4265 list_add_head(&gdi_font_list, &font->entry);
4268 /*************************************************************
4269 * create_child_font_list
4271 static BOOL create_child_font_list(GdiFont *font)
4274 SYSTEM_LINKS *font_link;
4275 CHILD_FONT *font_link_entry, *new_child;
4279 psub = get_font_subst(&font_subst_list, font->name, -1);
4280 font_name = psub ? psub->to.name : font->name;
4281 font_link = find_font_link(font_name);
4282 if (font_link != NULL)
4284 TRACE("found entry in system list\n");
4285 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4287 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4288 new_child->face = font_link_entry->face;
4289 new_child->font = NULL;
4290 list_add_tail(&font->child_fonts, &new_child->entry);
4291 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4296 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4297 * Sans Serif. This is how asian windows get default fallbacks for fonts
4299 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4300 font->charset != OEM_CHARSET &&
4301 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4303 font_link = find_font_link(szDefaultFallbackLink);
4304 if (font_link != NULL)
4306 TRACE("found entry in default fallback list\n");
4307 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4309 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4310 new_child->face = font_link_entry->face;
4311 new_child->font = NULL;
4312 list_add_tail(&font->child_fonts, &new_child->entry);
4313 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4322 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4324 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4326 if (pFT_Set_Charmap)
4329 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4331 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4333 for (i = 0; i < ft_face->num_charmaps; i++)
4335 if (ft_face->charmaps[i]->encoding == encoding)
4337 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4338 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4340 switch (ft_face->charmaps[i]->platform_id)
4343 cmap_def = ft_face->charmaps[i];
4345 case 0: /* Apple Unicode */
4346 cmap0 = ft_face->charmaps[i];
4348 case 1: /* Macintosh */
4349 cmap1 = ft_face->charmaps[i];
4352 cmap2 = ft_face->charmaps[i];
4354 case 3: /* Microsoft */
4355 cmap3 = ft_face->charmaps[i];
4360 if (cmap3) /* prefer Microsoft cmap table */
4361 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4363 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4365 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4367 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4369 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4371 return ft_err == FT_Err_Ok;
4374 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4378 /*************************************************************
4381 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4382 LPCWSTR output, const DEVMODEW *devmode )
4384 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4386 if (!physdev) return FALSE;
4387 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4392 /*************************************************************
4395 static BOOL freetype_DeleteDC( PHYSDEV dev )
4397 struct freetype_physdev *physdev = get_freetype_dev( dev );
4398 HeapFree( GetProcessHeap(), 0, physdev );
4403 /*************************************************************
4404 * freetype_SelectFont
4406 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4408 struct freetype_physdev *physdev = get_freetype_dev( dev );
4410 Face *face, *best, *best_bitmap;
4411 Family *family, *last_resort_family;
4412 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4413 INT height, width = 0;
4414 unsigned int score = 0, new_score;
4415 signed int diff = 0, newdiff;
4416 BOOL bd, it, can_use_bitmap, want_vertical;
4421 FontSubst *psub = NULL;
4422 DC *dc = get_dc_ptr( dev->hdc );
4423 const SYSTEM_LINKS *font_link;
4425 if (!hfont) /* notification that the font has been changed by another driver */
4428 physdev->font = NULL;
4429 release_dc_ptr( dc );
4433 GetObjectW( hfont, sizeof(lf), &lf );
4434 lf.lfWidth = abs(lf.lfWidth);
4436 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4438 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4439 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4440 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4443 if(dc->GraphicsMode == GM_ADVANCED)
4445 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4446 /* Try to avoid not necessary glyph transformations */
4447 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4449 lf.lfHeight *= fabs(dcmat.eM11);
4450 lf.lfWidth *= fabs(dcmat.eM11);
4451 dcmat.eM11 = dcmat.eM22 = 1.0;
4456 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4457 font scaling abilities. */
4458 dcmat.eM11 = dcmat.eM22 = 1.0;
4459 dcmat.eM21 = dcmat.eM12 = 0;
4460 if (dc->vport2WorldValid)
4462 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4463 lf.lfOrientation = -lf.lfOrientation;
4464 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4465 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4469 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4470 dcmat.eM21, dcmat.eM22);
4473 EnterCriticalSection( &freetype_cs );
4475 /* check the cache first */
4476 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4477 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4481 if(list_empty(&font_list)) /* No fonts installed */
4483 TRACE("No fonts installed\n");
4487 TRACE("not in cache\n");
4490 ret->font_desc.matrix = dcmat;
4491 ret->font_desc.lf = lf;
4492 ret->font_desc.can_use_bitmap = can_use_bitmap;
4493 calc_hash(&ret->font_desc);
4494 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4495 hflist->hfont = hfont;
4496 list_add_head(&ret->hfontlist, &hflist->entry);
4498 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4499 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4500 original value lfCharSet. Note this is a special case for
4501 Symbol and doesn't happen at least for "Wingdings*" */
4503 if(!strcmpiW(lf.lfFaceName, SymbolW))
4504 lf.lfCharSet = SYMBOL_CHARSET;
4506 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4507 switch(lf.lfCharSet) {
4508 case DEFAULT_CHARSET:
4509 csi.fs.fsCsb[0] = 0;
4512 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4513 csi.fs.fsCsb[0] = 0;
4519 if(lf.lfFaceName[0] != '\0') {
4520 CHILD_FONT *font_link_entry;
4521 LPWSTR FaceName = lf.lfFaceName;
4523 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4526 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4527 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4528 if (psub->to.charset != -1)
4529 lf.lfCharSet = psub->to.charset;
4532 /* We want a match on name and charset or just name if
4533 charset was DEFAULT_CHARSET. If the latter then
4534 we fixup the returned charset later in get_nearest_charset
4535 where we'll either use the charset of the current ansi codepage
4536 or if that's unavailable the first charset that the font supports.
4538 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4539 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4540 if (!strcmpiW(family->FamilyName, FaceName) ||
4541 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4543 font_link = find_font_link(family->FamilyName);
4544 face_list = get_face_list_from_family(family);
4545 LIST_FOR_EACH(face_elem_ptr, face_list) {
4546 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4547 if (!(face->scalable || can_use_bitmap))
4549 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4551 if (font_link != NULL &&
4552 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4554 if (!csi.fs.fsCsb[0])
4560 /* Search by full face name. */
4561 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4562 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4563 face_list = get_face_list_from_family(family);
4564 LIST_FOR_EACH(face_elem_ptr, face_list) {
4565 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4566 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4567 (face->scalable || can_use_bitmap))
4569 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4571 font_link = find_font_link(family->FamilyName);
4572 if (font_link != NULL &&
4573 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4580 * Try check the SystemLink list first for a replacement font.
4581 * We may find good replacements there.
4583 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4585 if(!strcmpiW(font_link->font_name, FaceName) ||
4586 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4588 TRACE("found entry in system list\n");
4589 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4591 const SYSTEM_LINKS *links;
4593 face = font_link_entry->face;
4594 if (!(face->scalable || can_use_bitmap))
4596 family = face->family;
4597 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4599 links = find_font_link(family->FamilyName);
4600 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4607 psub = NULL; /* substitution is no more relevant */
4609 /* If requested charset was DEFAULT_CHARSET then try using charset
4610 corresponding to the current ansi codepage */
4611 if (!csi.fs.fsCsb[0])
4614 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4615 FIXME("TCI failed on codepage %d\n", acp);
4616 csi.fs.fsCsb[0] = 0;
4618 lf.lfCharSet = csi.ciCharset;
4621 want_vertical = (lf.lfFaceName[0] == '@');
4623 /* Face families are in the top 4 bits of lfPitchAndFamily,
4624 so mask with 0xF0 before testing */
4626 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4627 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4628 strcpyW(lf.lfFaceName, defFixed);
4629 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4630 strcpyW(lf.lfFaceName, defSerif);
4631 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4632 strcpyW(lf.lfFaceName, defSans);
4634 strcpyW(lf.lfFaceName, defSans);
4635 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4636 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4637 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4638 font_link = find_font_link(family->FamilyName);
4639 face_list = get_face_list_from_family(family);
4640 LIST_FOR_EACH(face_elem_ptr, face_list) {
4641 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4642 if (!(face->scalable || can_use_bitmap))
4644 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4646 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4652 last_resort_family = NULL;
4653 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4654 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4655 font_link = find_font_link(family->FamilyName);
4656 face_list = get_face_list_from_family(family);
4657 LIST_FOR_EACH(face_elem_ptr, face_list) {
4658 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4659 if(face->vertical == want_vertical &&
4660 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4661 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4664 if(can_use_bitmap && !last_resort_family)
4665 last_resort_family = family;
4670 if(last_resort_family) {
4671 family = last_resort_family;
4672 csi.fs.fsCsb[0] = 0;
4676 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4677 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4678 face_list = get_face_list_from_family(family);
4679 LIST_FOR_EACH(face_elem_ptr, face_list) {
4680 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4681 if(face->scalable && face->vertical == want_vertical) {
4682 csi.fs.fsCsb[0] = 0;
4683 WARN("just using first face for now\n");
4686 if(can_use_bitmap && !last_resort_family)
4687 last_resort_family = family;
4690 if(!last_resort_family) {
4691 FIXME("can't find a single appropriate font - bailing\n");
4697 WARN("could only find a bitmap font - this will probably look awful!\n");
4698 family = last_resort_family;
4699 csi.fs.fsCsb[0] = 0;
4702 it = lf.lfItalic ? 1 : 0;
4703 bd = lf.lfWeight > 550 ? 1 : 0;
4705 height = lf.lfHeight;
4707 face = best = best_bitmap = NULL;
4708 font_link = find_font_link(family->FamilyName);
4709 face_list = get_face_list_from_family(family);
4710 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4712 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4713 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4718 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4719 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4720 new_score = (italic ^ it) + (bold ^ bd);
4721 if(!best || new_score <= score)
4723 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4724 italic, bold, it, bd);
4727 if(best->scalable && score == 0) break;
4731 newdiff = height - (signed int)(best->size.height);
4733 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4734 if(!best_bitmap || new_score < score ||
4735 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4737 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4740 if(score == 0 && diff == 0) break;
4747 face = best->scalable ? best : best_bitmap;
4748 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4749 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4752 height = lf.lfHeight;
4756 if(csi.fs.fsCsb[0]) {
4757 ret->charset = lf.lfCharSet;
4758 ret->codepage = csi.ciACP;
4761 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4763 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4764 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4766 ret->aveWidth = height ? lf.lfWidth : 0;
4768 if(!face->scalable) {
4769 /* Windows uses integer scaling factors for bitmap fonts */
4770 INT scale, scaled_height;
4771 GdiFont *cachedfont;
4773 /* FIXME: rotation of bitmap fonts is ignored */
4774 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4776 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4777 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4778 dcmat.eM11 = dcmat.eM22 = 1.0;
4779 /* As we changed the matrix, we need to search the cache for the font again,
4780 * otherwise we might explode the cache. */
4781 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4782 TRACE("Found cached font after non-scalable matrix rescale!\n");
4787 calc_hash(&ret->font_desc);
4789 if (height != 0) height = diff;
4790 height += face->size.height;
4792 scale = (height + face->size.height - 1) / face->size.height;
4793 scaled_height = scale * face->size.height;
4794 /* Only jump to the next height if the difference <= 25% original height */
4795 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4796 /* The jump between unscaled and doubled is delayed by 1 */
4797 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4798 ret->scale_y = scale;
4800 width = face->size.x_ppem >> 6;
4801 height = face->size.y_ppem >> 6;
4805 TRACE("font scale y: %f\n", ret->scale_y);
4807 ret->ft_face = OpenFontFace(ret, face, width, height);
4816 ret->ntmFlags = face->ntmFlags;
4818 if (ret->charset == SYMBOL_CHARSET &&
4819 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4822 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4826 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4829 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4830 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4831 ret->underline = lf.lfUnderline ? 0xff : 0;
4832 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4833 create_child_font_list(ret);
4835 if (face->vertical) /* We need to try to load the GSUB table */
4837 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4838 if (length != GDI_ERROR)
4840 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4841 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4842 TRACE("Loaded GSUB table of %i bytes\n",length);
4846 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4853 physdev->font = ret;
4855 LeaveCriticalSection( &freetype_cs );
4856 release_dc_ptr( dc );
4857 return ret ? hfont : 0;
4860 static void dump_gdi_font_list(void)
4863 struct list *elem_ptr;
4865 TRACE("---------- gdiFont Cache ----------\n");
4866 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4867 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4868 TRACE("gdiFont=%p %s %d\n",
4869 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4872 TRACE("---------- Unused gdiFont Cache ----------\n");
4873 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4874 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4875 TRACE("gdiFont=%p %s %d\n",
4876 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4879 TRACE("---------- Child gdiFont Cache ----------\n");
4880 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4881 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4882 TRACE("gdiFont=%p %s %d\n",
4883 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4887 /*************************************************************
4888 * WineEngDestroyFontInstance
4890 * free the gdiFont associated with this handle
4893 BOOL WineEngDestroyFontInstance(HFONT handle)
4898 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4902 EnterCriticalSection( &freetype_cs );
4904 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4906 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4907 while(hfontlist_elem_ptr) {
4908 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4909 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4910 if(hflist->hfont == handle) {
4911 TRACE("removing child font %p from child list\n", gdiFont);
4912 list_remove(&gdiFont->entry);
4913 LeaveCriticalSection( &freetype_cs );
4919 TRACE("destroying hfont=%p\n", handle);
4921 dump_gdi_font_list();
4923 font_elem_ptr = list_head(&gdi_font_list);
4924 while(font_elem_ptr) {
4925 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4926 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4928 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4929 while(hfontlist_elem_ptr) {
4930 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4931 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4932 if(hflist->hfont == handle) {
4933 list_remove(&hflist->entry);
4934 HeapFree(GetProcessHeap(), 0, hflist);
4938 if(list_empty(&gdiFont->hfontlist)) {
4939 TRACE("Moving to Unused list\n");
4940 list_remove(&gdiFont->entry);
4941 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4946 font_elem_ptr = list_head(&unused_gdi_font_list);
4947 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4948 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4949 while(font_elem_ptr) {
4950 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4951 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4952 TRACE("freeing %p\n", gdiFont);
4953 list_remove(&gdiFont->entry);
4956 LeaveCriticalSection( &freetype_cs );
4960 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4967 id += IDS_FIRST_SCRIPT;
4968 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4969 if (!rsrc) return 0;
4970 hMem = LoadResource( gdi32_module, rsrc );
4971 if (!hMem) return 0;
4973 p = LockResource( hMem );
4975 while (id--) p += *p + 1;
4977 i = min(LF_FACESIZE - 1, *p);
4978 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4984 /***************************************************
4985 * create_enum_charset_list
4987 * This function creates charset enumeration list because in DEFAULT_CHARSET
4988 * case, the ANSI codepage's charset takes precedence over other charsets.
4989 * This function works as a filter other than DEFAULT_CHARSET case.
4991 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4996 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4997 csi.fs.fsCsb[0] != 0) {
4998 list->element[n].mask = csi.fs.fsCsb[0];
4999 list->element[n].charset = csi.ciCharset;
5000 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5003 else { /* charset is DEFAULT_CHARSET or invalid. */
5006 /* Set the current codepage's charset as the first element. */
5008 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5009 csi.fs.fsCsb[0] != 0) {
5010 list->element[n].mask = csi.fs.fsCsb[0];
5011 list->element[n].charset = csi.ciCharset;
5012 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5016 /* Fill out left elements. */
5017 for (i = 0; i < 32; i++) {
5019 fs.fsCsb[0] = 1L << i;
5021 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
5022 continue; /* skip, already added. */
5023 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5024 continue; /* skip, this is an invalid fsCsb bit. */
5026 list->element[n].mask = fs.fsCsb[0];
5027 list->element[n].charset = csi.ciCharset;
5028 load_script_name( i, list->element[n].name );
5037 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5038 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5043 if (face->cached_enum_data)
5046 *pelf = face->cached_enum_data->elf;
5047 *pntm = face->cached_enum_data->ntm;
5048 *ptype = face->cached_enum_data->type;
5052 font = alloc_font();
5054 if(face->scalable) {
5058 height = face->size.y_ppem >> 6;
5059 width = face->size.x_ppem >> 6;
5061 font->scale_y = 1.0;
5063 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5069 font->name = strdupW(face->family->FamilyName);
5070 font->ntmFlags = face->ntmFlags;
5072 if (get_outline_text_metrics(font))
5074 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5076 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5077 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5078 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5080 lstrcpynW(pelf->elfLogFont.lfFaceName,
5081 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5083 lstrcpynW(pelf->elfFullName,
5084 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5086 lstrcpynW(pelf->elfStyle,
5087 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5092 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5094 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5095 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5096 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5098 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5100 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5102 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5103 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5106 pntm->ntmTm.ntmFlags = face->ntmFlags;
5107 pntm->ntmFontSig = face->fs;
5109 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5111 pelf->elfLogFont.lfEscapement = 0;
5112 pelf->elfLogFont.lfOrientation = 0;
5113 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5114 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5115 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5116 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5117 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5118 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5119 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5120 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5121 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5122 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5123 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5126 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5127 *ptype |= TRUETYPE_FONTTYPE;
5128 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5129 *ptype |= DEVICE_FONTTYPE;
5130 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5131 *ptype |= RASTER_FONTTYPE;
5133 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5134 if (face->cached_enum_data)
5136 face->cached_enum_data->elf = *pelf;
5137 face->cached_enum_data->ntm = *pntm;
5138 face->cached_enum_data->type = *ptype;
5144 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5146 const struct list *face_list, *face_elem_ptr;
5148 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5150 face_list = get_face_list_from_family(family);
5151 LIST_FOR_EACH(face_elem_ptr, face_list)
5153 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5155 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5161 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5163 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5165 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5168 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5169 FONTENUMPROCW proc, LPARAM lparam)
5172 NEWTEXTMETRICEXW ntm;
5176 GetEnumStructs(face, &elf, &ntm, &type);
5177 for(i = 0; i < list->total; i++) {
5178 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5179 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5180 load_script_name( IDS_OEM_DOS, elf.elfScript );
5181 i = list->total; /* break out of loop after enumeration */
5182 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
5185 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5186 strcpyW(elf.elfScript, list->element[i].name);
5187 if (!elf.elfScript[0])
5188 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5190 /* Font Replacement */
5191 if (family != face->family)
5193 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5195 strcpyW(elf.elfFullName, face->FullName);
5197 strcpyW(elf.elfFullName, family->FamilyName);
5199 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5200 debugstr_w(elf.elfLogFont.lfFaceName),
5201 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5202 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5203 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5204 ntm.ntmTm.ntmFlags);
5205 /* release section before callback (FIXME) */
5206 LeaveCriticalSection( &freetype_cs );
5207 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5208 EnterCriticalSection( &freetype_cs );
5213 /*************************************************************
5214 * freetype_EnumFonts
5216 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5220 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5222 struct enum_charset_list enum_charsets;
5226 lf.lfCharSet = DEFAULT_CHARSET;
5227 lf.lfPitchAndFamily = 0;
5228 lf.lfFaceName[0] = 0;
5232 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5234 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5237 EnterCriticalSection( &freetype_cs );
5238 if(plf->lfFaceName[0]) {
5240 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5243 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5244 debugstr_w(psub->to.name));
5246 strcpyW(lf.lfFaceName, psub->to.name);
5250 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5251 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5252 if(family_matches(family, plf)) {
5253 face_list = get_face_list_from_family(family);
5254 LIST_FOR_EACH(face_elem_ptr, face_list) {
5255 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5256 if (!face_matches(family->FamilyName, face, plf)) continue;
5257 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5262 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5263 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5264 face_list = get_face_list_from_family(family);
5265 face_elem_ptr = list_head(face_list);
5266 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5267 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5270 LeaveCriticalSection( &freetype_cs );
5274 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5276 pt->x.value = vec->x >> 6;
5277 pt->x.fract = (vec->x & 0x3f) << 10;
5278 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5279 pt->y.value = vec->y >> 6;
5280 pt->y.fract = (vec->y & 0x3f) << 10;
5281 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5285 /***************************************************
5286 * According to the MSDN documentation on WideCharToMultiByte,
5287 * certain codepages cannot set the default_used parameter.
5288 * This returns TRUE if the codepage can set that parameter, false else
5289 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5291 static BOOL codepage_sets_default_used(UINT codepage)
5305 * GSUB Table handling functions
5308 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5310 const GSUB_CoverageFormat1* cf1;
5314 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5316 int count = GET_BE_WORD(cf1->GlyphCount);
5318 TRACE("Coverage Format 1, %i glyphs\n",count);
5319 for (i = 0; i < count; i++)
5320 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5324 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5326 const GSUB_CoverageFormat2* cf2;
5329 cf2 = (const GSUB_CoverageFormat2*)cf1;
5331 count = GET_BE_WORD(cf2->RangeCount);
5332 TRACE("Coverage Format 2, %i ranges\n",count);
5333 for (i = 0; i < count; i++)
5335 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5337 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5338 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5340 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5341 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5347 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5352 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5354 const GSUB_ScriptList *script;
5355 const GSUB_Script *deflt = NULL;
5357 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5359 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5360 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5362 const GSUB_Script *scr;
5365 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5366 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5368 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5370 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5376 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5380 const GSUB_LangSys *Lang;
5382 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5384 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5386 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5387 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5389 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5392 offset = GET_BE_WORD(script->DefaultLangSys);
5395 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5401 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5404 const GSUB_FeatureList *feature;
5405 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5407 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5408 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5410 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5411 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5413 const GSUB_Feature *feat;
5414 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5421 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5425 const GSUB_LookupList *lookup;
5426 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5428 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5429 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5431 const GSUB_LookupTable *look;
5432 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5433 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5434 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5435 if (GET_BE_WORD(look->LookupType) != 1)
5436 FIXME("We only handle SubType 1\n");
5441 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5443 const GSUB_SingleSubstFormat1 *ssf1;
5444 offset = GET_BE_WORD(look->SubTable[j]);
5445 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5446 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5448 int offset = GET_BE_WORD(ssf1->Coverage);
5449 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5450 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5452 TRACE(" Glyph 0x%x ->",glyph);
5453 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5454 TRACE(" 0x%x\n",glyph);
5459 const GSUB_SingleSubstFormat2 *ssf2;
5463 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5464 offset = GET_BE_WORD(ssf1->Coverage);
5465 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5466 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5467 TRACE(" Coverage index %i\n",index);
5470 TRACE(" Glyph is 0x%x ->",glyph);
5471 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5472 TRACE("0x%x\n",glyph);
5481 static const char* get_opentype_script(const GdiFont *font)
5484 * I am not sure if this is the correct way to generate our script tag
5487 switch (font->charset)
5489 case ANSI_CHARSET: return "latn";
5490 case BALTIC_CHARSET: return "latn"; /* ?? */
5491 case CHINESEBIG5_CHARSET: return "hani";
5492 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5493 case GB2312_CHARSET: return "hani";
5494 case GREEK_CHARSET: return "grek";
5495 case HANGUL_CHARSET: return "hang";
5496 case RUSSIAN_CHARSET: return "cyrl";
5497 case SHIFTJIS_CHARSET: return "kana";
5498 case TURKISH_CHARSET: return "latn"; /* ?? */
5499 case VIETNAMESE_CHARSET: return "latn";
5500 case JOHAB_CHARSET: return "latn"; /* ?? */
5501 case ARABIC_CHARSET: return "arab";
5502 case HEBREW_CHARSET: return "hebr";
5503 case THAI_CHARSET: return "thai";
5504 default: return "latn";
5508 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5510 const GSUB_Header *header;
5511 const GSUB_Script *script;
5512 const GSUB_LangSys *language;
5513 const GSUB_Feature *feature;
5515 if (!font->GSUB_Table)
5518 header = font->GSUB_Table;
5520 script = GSUB_get_script_table(header, get_opentype_script(font));
5523 TRACE("Script not found\n");
5526 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5529 TRACE("Language not found\n");
5532 feature = GSUB_get_feature(header, language, "vrt2");
5534 feature = GSUB_get_feature(header, language, "vert");
5537 TRACE("vrt2/vert feature not found\n");
5540 return GSUB_apply_feature(header, feature, glyph);
5543 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5547 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5548 WCHAR wc = (WCHAR)glyph;
5550 BOOL *default_used_pointer;
5553 default_used_pointer = NULL;
5554 default_used = FALSE;
5555 if (codepage_sets_default_used(font->codepage))
5556 default_used_pointer = &default_used;
5557 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5560 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5561 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5565 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5567 if (glyph < 0x100) glyph += 0xf000;
5568 /* there is a number of old pre-Unicode "broken" TTFs, which
5569 do have symbols at U+00XX instead of U+f0XX */
5570 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5571 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5573 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5578 /*************************************************************
5579 * freetype_GetGlyphIndices
5581 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5583 struct freetype_physdev *physdev = get_freetype_dev( dev );
5586 BOOL got_default = FALSE;
5590 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5591 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5594 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5596 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5601 EnterCriticalSection( &freetype_cs );
5603 for(i = 0; i < count; i++)
5605 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5610 if (FT_IS_SFNT(physdev->font->ft_face))
5612 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5613 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5618 get_text_metrics(physdev->font, &textm);
5619 default_char = textm.tmDefaultChar;
5623 pgi[i] = default_char;
5626 LeaveCriticalSection( &freetype_cs );
5630 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5632 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5633 return !memcmp(matrix, &identity, sizeof(FMAT2));
5636 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5638 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5639 return !memcmp(matrix, &identity, sizeof(MAT2));
5642 static inline BYTE get_max_level( UINT format )
5646 case GGO_GRAY2_BITMAP: return 4;
5647 case GGO_GRAY4_BITMAP: return 16;
5648 case GGO_GRAY8_BITMAP: return 64;
5653 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5655 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5656 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5659 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5660 FT_Face ft_face = incoming_font->ft_face;
5661 GdiFont *font = incoming_font;
5662 FT_UInt glyph_index;
5663 DWORD width, height, pitch, needed = 0;
5664 FT_Bitmap ft_bitmap;
5666 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5668 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5669 double widthRatio = 1.0;
5670 FT_Matrix transMat = identityMat;
5671 FT_Matrix transMatUnrotated;
5672 BOOL needsTransform = FALSE;
5673 BOOL tategaki = (font->GSUB_Table != NULL);
5674 UINT original_index;
5676 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5677 buflen, buf, lpmat);
5679 TRACE("font transform %f %f %f %f\n",
5680 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5681 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5683 if(format & GGO_GLYPH_INDEX) {
5684 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5685 original_index = glyph;
5686 format &= ~GGO_GLYPH_INDEX;
5688 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5689 ft_face = font->ft_face;
5690 original_index = glyph_index;
5693 if(format & GGO_UNHINTED) {
5694 load_flags |= FT_LOAD_NO_HINTING;
5695 format &= ~GGO_UNHINTED;
5698 /* tategaki never appears to happen to lower glyph index */
5699 if (glyph_index < TATEGAKI_LOWER_BOUND )
5702 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5703 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5704 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5705 font->gmsize * sizeof(GM*));
5707 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5708 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5710 *lpgm = FONT_GM(font,original_index)->gm;
5711 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5712 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5713 lpgm->gmCellIncX, lpgm->gmCellIncY);
5714 return 1; /* FIXME */
5718 if (!font->gm[original_index / GM_BLOCK_SIZE])
5719 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5721 /* Scaling factor */
5726 get_text_metrics(font, &tm);
5728 widthRatio = (double)font->aveWidth;
5729 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5732 widthRatio = font->scale_y;
5734 /* Scaling transform */
5735 if (widthRatio != 1.0 || font->scale_y != 1.0)
5738 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5741 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5743 pFT_Matrix_Multiply(&scaleMat, &transMat);
5744 needsTransform = TRUE;
5747 /* Slant transform */
5748 if (font->fake_italic) {
5751 slantMat.xx = (1 << 16);
5752 slantMat.xy = ((1 << 16) >> 2);
5754 slantMat.yy = (1 << 16);
5755 pFT_Matrix_Multiply(&slantMat, &transMat);
5756 needsTransform = TRUE;
5759 /* Rotation transform */
5760 transMatUnrotated = transMat;
5761 if(font->orientation && !tategaki) {
5762 FT_Matrix rotationMat;
5764 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5765 pFT_Vector_Unit(&vecAngle, angle);
5766 rotationMat.xx = vecAngle.x;
5767 rotationMat.xy = -vecAngle.y;
5768 rotationMat.yx = -rotationMat.xy;
5769 rotationMat.yy = rotationMat.xx;
5771 pFT_Matrix_Multiply(&rotationMat, &transMat);
5772 needsTransform = TRUE;
5775 /* World transform */
5776 if (!is_identity_FMAT2(&font->font_desc.matrix))
5779 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5780 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5781 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5782 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5783 pFT_Matrix_Multiply(&worldMat, &transMat);
5784 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5785 needsTransform = TRUE;
5788 /* Extra transformation specified by caller */
5789 if (!is_identity_MAT2(lpmat))
5792 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5793 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5794 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5795 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5796 pFT_Matrix_Multiply(&extraMat, &transMat);
5797 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5798 needsTransform = TRUE;
5801 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5802 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5803 format == GGO_GRAY8_BITMAP))
5805 load_flags |= FT_LOAD_NO_BITMAP;
5808 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5811 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5815 if(!needsTransform) {
5816 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5817 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5818 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5820 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5821 bottom = (ft_face->glyph->metrics.horiBearingY -
5822 ft_face->glyph->metrics.height) & -64;
5823 lpgm->gmCellIncX = adv;
5824 lpgm->gmCellIncY = 0;
5831 for(xc = 0; xc < 2; xc++) {
5832 for(yc = 0; yc < 2; yc++) {
5833 vec.x = (ft_face->glyph->metrics.horiBearingX +
5834 xc * ft_face->glyph->metrics.width);
5835 vec.y = ft_face->glyph->metrics.horiBearingY -
5836 yc * ft_face->glyph->metrics.height;
5837 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5838 pFT_Vector_Transform(&vec, &transMat);
5839 if(xc == 0 && yc == 0) {
5840 left = right = vec.x;
5841 top = bottom = vec.y;
5843 if(vec.x < left) left = vec.x;
5844 else if(vec.x > right) right = vec.x;
5845 if(vec.y < bottom) bottom = vec.y;
5846 else if(vec.y > top) top = vec.y;
5851 right = (right + 63) & -64;
5852 bottom = bottom & -64;
5853 top = (top + 63) & -64;
5855 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5856 vec.x = ft_face->glyph->metrics.horiAdvance;
5858 pFT_Vector_Transform(&vec, &transMat);
5859 lpgm->gmCellIncX = (vec.x+63) >> 6;
5860 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5862 vec.x = ft_face->glyph->metrics.horiAdvance;
5864 pFT_Vector_Transform(&vec, &transMatUnrotated);
5865 adv = (vec.x+63) >> 6;
5869 bbx = (right - left) >> 6;
5870 lpgm->gmBlackBoxX = (right - left) >> 6;
5871 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5872 lpgm->gmptGlyphOrigin.x = left >> 6;
5873 lpgm->gmptGlyphOrigin.y = top >> 6;
5875 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5876 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5877 lpgm->gmCellIncX, lpgm->gmCellIncY);
5879 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5880 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5882 FONT_GM(font,original_index)->gm = *lpgm;
5883 FONT_GM(font,original_index)->adv = adv;
5884 FONT_GM(font,original_index)->lsb = lsb;
5885 FONT_GM(font,original_index)->bbx = bbx;
5886 FONT_GM(font,original_index)->init = TRUE;
5889 if(format == GGO_METRICS)
5891 return 1; /* FIXME */
5894 if(ft_face->glyph->format != ft_glyph_format_outline &&
5895 (format == GGO_NATIVE || format == GGO_BEZIER))
5897 TRACE("loaded a bitmap\n");
5903 width = lpgm->gmBlackBoxX;
5904 height = lpgm->gmBlackBoxY;
5905 pitch = ((width + 31) >> 5) << 2;
5906 needed = pitch * height;
5908 if(!buf || !buflen) break;
5910 switch(ft_face->glyph->format) {
5911 case ft_glyph_format_bitmap:
5913 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5914 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5915 INT h = ft_face->glyph->bitmap.rows;
5917 memcpy(dst, src, w);
5918 src += ft_face->glyph->bitmap.pitch;
5924 case ft_glyph_format_outline:
5925 ft_bitmap.width = width;
5926 ft_bitmap.rows = height;
5927 ft_bitmap.pitch = pitch;
5928 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5929 ft_bitmap.buffer = buf;
5932 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5934 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5936 /* Note: FreeType will only set 'black' bits for us. */
5937 memset(buf, 0, needed);
5938 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5942 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5947 case GGO_GRAY2_BITMAP:
5948 case GGO_GRAY4_BITMAP:
5949 case GGO_GRAY8_BITMAP:
5950 case WINE_GGO_GRAY16_BITMAP:
5952 unsigned int max_level, row, col;
5955 width = lpgm->gmBlackBoxX;
5956 height = lpgm->gmBlackBoxY;
5957 pitch = (width + 3) / 4 * 4;
5958 needed = pitch * height;
5960 if(!buf || !buflen) break;
5962 max_level = get_max_level( format );
5964 switch(ft_face->glyph->format) {
5965 case ft_glyph_format_bitmap:
5967 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5968 INT h = ft_face->glyph->bitmap.rows;
5970 memset( buf, 0, needed );
5972 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5973 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5974 src += ft_face->glyph->bitmap.pitch;
5979 case ft_glyph_format_outline:
5981 ft_bitmap.width = width;
5982 ft_bitmap.rows = height;
5983 ft_bitmap.pitch = pitch;
5984 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5985 ft_bitmap.buffer = buf;
5988 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5990 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5992 memset(ft_bitmap.buffer, 0, buflen);
5994 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5996 if (max_level != 255)
5998 for (row = 0, start = buf; row < height; row++)
6000 for (col = 0, ptr = start; col < width; col++, ptr++)
6001 *ptr = (((int)*ptr) * max_level + 128) / 256;
6009 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6015 case WINE_GGO_HRGB_BITMAP:
6016 case WINE_GGO_HBGR_BITMAP:
6017 case WINE_GGO_VRGB_BITMAP:
6018 case WINE_GGO_VBGR_BITMAP:
6019 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6021 switch (ft_face->glyph->format)
6023 case FT_GLYPH_FORMAT_BITMAP:
6028 width = lpgm->gmBlackBoxX;
6029 height = lpgm->gmBlackBoxY;
6031 needed = pitch * height;
6033 if (!buf || !buflen) break;
6035 memset(buf, 0, buflen);
6037 src = ft_face->glyph->bitmap.buffer;
6038 src_pitch = ft_face->glyph->bitmap.pitch;
6040 height = min( height, ft_face->glyph->bitmap.rows );
6043 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6045 if ( src[x / 8] & masks[x % 8] )
6046 ((unsigned int *)dst)[x] = ~0u;
6055 case FT_GLYPH_FORMAT_OUTLINE:
6059 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6060 INT x_shift, y_shift;
6062 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6063 FT_Render_Mode render_mode =
6064 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6065 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6067 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6069 if ( render_mode == FT_RENDER_MODE_LCD)
6071 lpgm->gmBlackBoxX += 2;
6072 lpgm->gmptGlyphOrigin.x -= 1;
6076 lpgm->gmBlackBoxY += 2;
6077 lpgm->gmptGlyphOrigin.y += 1;
6081 width = lpgm->gmBlackBoxX;
6082 height = lpgm->gmBlackBoxY;
6084 needed = pitch * height;
6086 if (!buf || !buflen) break;
6088 memset(buf, 0, buflen);
6090 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6092 if ( needsTransform )
6093 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6095 if ( pFT_Library_SetLcdFilter )
6096 pFT_Library_SetLcdFilter( library, lcdfilter );
6097 pFT_Render_Glyph (ft_face->glyph, render_mode);
6099 src = ft_face->glyph->bitmap.buffer;
6100 src_pitch = ft_face->glyph->bitmap.pitch;
6101 src_width = ft_face->glyph->bitmap.width;
6102 src_height = ft_face->glyph->bitmap.rows;
6104 if ( render_mode == FT_RENDER_MODE_LCD)
6112 rgb_interval = src_pitch;
6117 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6118 if ( x_shift < 0 ) x_shift = 0;
6119 if ( x_shift + (src_width / hmul) > width )
6120 x_shift = width - (src_width / hmul);
6122 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6123 if ( y_shift < 0 ) y_shift = 0;
6124 if ( y_shift + (src_height / vmul) > height )
6125 y_shift = height - (src_height / vmul);
6127 dst += x_shift + y_shift * ( pitch / 4 );
6128 while ( src_height )
6130 for ( x = 0; x < src_width / hmul; x++ )
6134 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6135 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6136 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6137 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6141 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6142 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6143 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6144 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6147 src += src_pitch * vmul;
6156 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6168 int contour, point = 0, first_pt;
6169 FT_Outline *outline = &ft_face->glyph->outline;
6170 TTPOLYGONHEADER *pph;
6172 DWORD pph_start, cpfx, type;
6174 if(buflen == 0) buf = NULL;
6176 if (needsTransform && buf) {
6177 pFT_Outline_Transform(outline, &transMat);
6180 for(contour = 0; contour < outline->n_contours; contour++) {
6182 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6185 pph->dwType = TT_POLYGON_TYPE;
6186 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6188 needed += sizeof(*pph);
6190 while(point <= outline->contours[contour]) {
6191 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6192 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6193 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6197 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6200 } while(point <= outline->contours[contour] &&
6201 (outline->tags[point] & FT_Curve_Tag_On) ==
6202 (outline->tags[point-1] & FT_Curve_Tag_On));
6203 /* At the end of a contour Windows adds the start point, but
6205 if(point > outline->contours[contour] &&
6206 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6208 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6210 } else if(point <= outline->contours[contour] &&
6211 outline->tags[point] & FT_Curve_Tag_On) {
6212 /* add closing pt for bezier */
6214 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6222 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6225 pph->cb = needed - pph_start;
6231 /* Convert the quadratic Beziers to cubic Beziers.
6232 The parametric eqn for a cubic Bezier is, from PLRM:
6233 r(t) = at^3 + bt^2 + ct + r0
6234 with the control points:
6239 A quadratic Bezier has the form:
6240 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6242 So equating powers of t leads to:
6243 r1 = 2/3 p1 + 1/3 p0
6244 r2 = 2/3 p1 + 1/3 p2
6245 and of course r0 = p0, r3 = p2
6248 int contour, point = 0, first_pt;
6249 FT_Outline *outline = &ft_face->glyph->outline;
6250 TTPOLYGONHEADER *pph;
6252 DWORD pph_start, cpfx, type;
6253 FT_Vector cubic_control[4];
6254 if(buflen == 0) buf = NULL;
6256 if (needsTransform && buf) {
6257 pFT_Outline_Transform(outline, &transMat);
6260 for(contour = 0; contour < outline->n_contours; contour++) {
6262 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6265 pph->dwType = TT_POLYGON_TYPE;
6266 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6268 needed += sizeof(*pph);
6270 while(point <= outline->contours[contour]) {
6271 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6272 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6273 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6276 if(type == TT_PRIM_LINE) {
6278 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6282 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6285 /* FIXME: Possible optimization in endpoint calculation
6286 if there are two consecutive curves */
6287 cubic_control[0] = outline->points[point-1];
6288 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6289 cubic_control[0].x += outline->points[point].x + 1;
6290 cubic_control[0].y += outline->points[point].y + 1;
6291 cubic_control[0].x >>= 1;
6292 cubic_control[0].y >>= 1;
6294 if(point+1 > outline->contours[contour])
6295 cubic_control[3] = outline->points[first_pt];
6297 cubic_control[3] = outline->points[point+1];
6298 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6299 cubic_control[3].x += outline->points[point].x + 1;
6300 cubic_control[3].y += outline->points[point].y + 1;
6301 cubic_control[3].x >>= 1;
6302 cubic_control[3].y >>= 1;
6305 /* r1 = 1/3 p0 + 2/3 p1
6306 r2 = 1/3 p2 + 2/3 p1 */
6307 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6308 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6309 cubic_control[2] = cubic_control[1];
6310 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6311 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6312 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6313 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6315 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6316 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6317 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6322 } while(point <= outline->contours[contour] &&
6323 (outline->tags[point] & FT_Curve_Tag_On) ==
6324 (outline->tags[point-1] & FT_Curve_Tag_On));
6325 /* At the end of a contour Windows adds the start point,
6326 but only for Beziers and we've already done that.
6328 if(point <= outline->contours[contour] &&
6329 outline->tags[point] & FT_Curve_Tag_On) {
6330 /* This is the closing pt of a bezier, but we've already
6331 added it, so just inc point and carry on */
6338 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6341 pph->cb = needed - pph_start;
6347 FIXME("Unsupported format %d\n", format);
6353 static BOOL get_bitmap_text_metrics(GdiFont *font)
6355 FT_Face ft_face = font->ft_face;
6356 FT_WinFNT_HeaderRec winfnt_header;
6357 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6358 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6359 font->potm->otmSize = size;
6361 #define TM font->potm->otmTextMetrics
6362 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6364 TM.tmHeight = winfnt_header.pixel_height;
6365 TM.tmAscent = winfnt_header.ascent;
6366 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6367 TM.tmInternalLeading = winfnt_header.internal_leading;
6368 TM.tmExternalLeading = winfnt_header.external_leading;
6369 TM.tmAveCharWidth = winfnt_header.avg_width;
6370 TM.tmMaxCharWidth = winfnt_header.max_width;
6371 TM.tmWeight = winfnt_header.weight;
6373 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6374 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6375 TM.tmFirstChar = winfnt_header.first_char;
6376 TM.tmLastChar = winfnt_header.last_char;
6377 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6378 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6379 TM.tmItalic = winfnt_header.italic;
6380 TM.tmUnderlined = font->underline;
6381 TM.tmStruckOut = font->strikeout;
6382 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6383 TM.tmCharSet = winfnt_header.charset;
6387 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6388 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6389 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6390 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6391 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6392 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6393 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6394 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6396 TM.tmDigitizedAspectX = 96; /* FIXME */
6397 TM.tmDigitizedAspectY = 96; /* FIXME */
6399 TM.tmLastChar = 255;
6400 TM.tmDefaultChar = 32;
6401 TM.tmBreakChar = 32;
6402 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6403 TM.tmUnderlined = font->underline;
6404 TM.tmStruckOut = font->strikeout;
6405 /* NB inverted meaning of TMPF_FIXED_PITCH */
6406 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6407 TM.tmCharSet = font->charset;
6415 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6417 double scale_x, scale_y;
6421 scale_x = (double)font->aveWidth;
6422 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6425 scale_x = font->scale_y;
6427 scale_x *= fabs(font->font_desc.matrix.eM11);
6428 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6430 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6431 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6433 SCALE_Y(ptm->tmHeight);
6434 SCALE_Y(ptm->tmAscent);
6435 SCALE_Y(ptm->tmDescent);
6436 SCALE_Y(ptm->tmInternalLeading);
6437 SCALE_Y(ptm->tmExternalLeading);
6438 SCALE_Y(ptm->tmOverhang);
6440 SCALE_X(ptm->tmAveCharWidth);
6441 SCALE_X(ptm->tmMaxCharWidth);
6447 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6449 double scale_x, scale_y;
6453 scale_x = (double)font->aveWidth;
6454 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6457 scale_x = font->scale_y;
6459 scale_x *= fabs(font->font_desc.matrix.eM11);
6460 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6462 scale_font_metrics(font, &potm->otmTextMetrics);
6464 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6465 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6467 SCALE_Y(potm->otmAscent);
6468 SCALE_Y(potm->otmDescent);
6469 SCALE_Y(potm->otmLineGap);
6470 SCALE_Y(potm->otmsCapEmHeight);
6471 SCALE_Y(potm->otmsXHeight);
6472 SCALE_Y(potm->otmrcFontBox.top);
6473 SCALE_Y(potm->otmrcFontBox.bottom);
6474 SCALE_X(potm->otmrcFontBox.left);
6475 SCALE_X(potm->otmrcFontBox.right);
6476 SCALE_Y(potm->otmMacAscent);
6477 SCALE_Y(potm->otmMacDescent);
6478 SCALE_Y(potm->otmMacLineGap);
6479 SCALE_X(potm->otmptSubscriptSize.x);
6480 SCALE_Y(potm->otmptSubscriptSize.y);
6481 SCALE_X(potm->otmptSubscriptOffset.x);
6482 SCALE_Y(potm->otmptSubscriptOffset.y);
6483 SCALE_X(potm->otmptSuperscriptSize.x);
6484 SCALE_Y(potm->otmptSuperscriptSize.y);
6485 SCALE_X(potm->otmptSuperscriptOffset.x);
6486 SCALE_Y(potm->otmptSuperscriptOffset.y);
6487 SCALE_Y(potm->otmsStrikeoutSize);
6488 SCALE_Y(potm->otmsStrikeoutPosition);
6489 SCALE_Y(potm->otmsUnderscoreSize);
6490 SCALE_Y(potm->otmsUnderscorePosition);
6496 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6500 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6502 /* Make sure that the font has sane width/height ratio */
6505 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6507 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6512 *ptm = font->potm->otmTextMetrics;
6513 scale_font_metrics(font, ptm);
6517 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6521 for(i = 0; i < ft_face->num_charmaps; i++)
6523 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6529 static BOOL get_outline_text_metrics(GdiFont *font)
6532 FT_Face ft_face = font->ft_face;
6533 UINT needed, lenfam, lensty, lenface, lenfull;
6535 TT_HoriHeader *pHori;
6536 TT_Postscript *pPost;
6537 FT_Fixed x_scale, y_scale;
6538 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6540 INT ascent, descent;
6542 TRACE("font=%p\n", font);
6544 if(!FT_IS_SCALABLE(ft_face))
6547 needed = sizeof(*font->potm);
6549 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6550 family_nameW = strdupW(font->name);
6552 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6554 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6555 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6556 style_nameW, lensty/sizeof(WCHAR));
6558 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6560 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6563 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6564 face_nameW = strdupW(font->name);
6566 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6568 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6571 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6572 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6573 full_nameW = strdupW(fake_nameW);
6575 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6577 /* These names should be read from the TT name table */
6579 /* length of otmpFamilyName */
6582 /* length of otmpFaceName */
6585 /* length of otmpStyleName */
6588 /* length of otmpFullName */
6592 x_scale = ft_face->size->metrics.x_scale;
6593 y_scale = ft_face->size->metrics.y_scale;
6595 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6597 FIXME("Can't find OS/2 table - not TT font?\n");
6601 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6603 FIXME("Can't find HHEA table - not TT font?\n");
6607 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6609 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6610 pOS2->usWinAscent, pOS2->usWinDescent,
6611 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6612 pOS2->xAvgCharWidth,
6613 ft_face->ascender, ft_face->descender, ft_face->height,
6614 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6615 ft_face->bbox.yMax, ft_face->bbox.yMin);
6617 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6618 font->potm->otmSize = needed;
6620 #define TM font->potm->otmTextMetrics
6622 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6623 ascent = pHori->Ascender;
6624 descent = -pHori->Descender;
6626 ascent = pOS2->usWinAscent;
6627 descent = pOS2->usWinDescent;
6630 font->ntmCellHeight = ascent + descent;
6631 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6634 TM.tmAscent = font->yMax;
6635 TM.tmDescent = -font->yMin;
6636 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6638 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6639 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6640 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6641 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6644 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6647 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6649 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6650 ((ascent + descent) -
6651 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6653 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6654 if (TM.tmAveCharWidth == 0) {
6655 TM.tmAveCharWidth = 1;
6657 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6658 TM.tmWeight = FW_REGULAR;
6659 if (font->fake_bold)
6660 TM.tmWeight = FW_BOLD;
6663 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6665 if (pOS2->usWeightClass > FW_MEDIUM)
6666 TM.tmWeight = pOS2->usWeightClass;
6668 else if (pOS2->usWeightClass <= FW_MEDIUM)
6669 TM.tmWeight = pOS2->usWeightClass;
6672 TM.tmDigitizedAspectX = 96; /* FIXME */
6673 TM.tmDigitizedAspectY = 96; /* FIXME */
6674 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6675 * symbol range to 0 - f0ff
6678 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6683 case 1257: /* Baltic */
6684 TM.tmLastChar = 0xf8fd;
6687 TM.tmLastChar = 0xf0ff;
6689 TM.tmBreakChar = 0x20;
6690 TM.tmDefaultChar = 0x1f;
6694 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6695 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6697 if(pOS2->usFirstCharIndex <= 1)
6698 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6699 else if (pOS2->usFirstCharIndex > 0xff)
6700 TM.tmBreakChar = 0x20;
6702 TM.tmBreakChar = pOS2->usFirstCharIndex;
6703 TM.tmDefaultChar = TM.tmBreakChar - 1;
6705 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6706 TM.tmUnderlined = font->underline;
6707 TM.tmStruckOut = font->strikeout;
6709 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6710 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6711 (pOS2->version == 0xFFFFU ||
6712 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6713 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6715 TM.tmPitchAndFamily = 0;
6717 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6719 case PAN_FAMILY_SCRIPT:
6720 TM.tmPitchAndFamily |= FF_SCRIPT;
6723 case PAN_FAMILY_DECORATIVE:
6724 TM.tmPitchAndFamily |= FF_DECORATIVE;
6729 case PAN_FAMILY_TEXT_DISPLAY:
6730 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6731 /* which is clearly not what the panose spec says. */
6733 if(TM.tmPitchAndFamily == 0 || /* fixed */
6734 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6735 TM.tmPitchAndFamily = FF_MODERN;
6738 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6743 TM.tmPitchAndFamily |= FF_DONTCARE;
6746 case PAN_SERIF_COVE:
6747 case PAN_SERIF_OBTUSE_COVE:
6748 case PAN_SERIF_SQUARE_COVE:
6749 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6750 case PAN_SERIF_SQUARE:
6751 case PAN_SERIF_THIN:
6752 case PAN_SERIF_BONE:
6753 case PAN_SERIF_EXAGGERATED:
6754 case PAN_SERIF_TRIANGLE:
6755 TM.tmPitchAndFamily |= FF_ROMAN;
6758 case PAN_SERIF_NORMAL_SANS:
6759 case PAN_SERIF_OBTUSE_SANS:
6760 case PAN_SERIF_PERP_SANS:
6761 case PAN_SERIF_FLARED:
6762 case PAN_SERIF_ROUNDED:
6763 TM.tmPitchAndFamily |= FF_SWISS;
6770 if(FT_IS_SCALABLE(ft_face))
6771 TM.tmPitchAndFamily |= TMPF_VECTOR;
6773 if(FT_IS_SFNT(ft_face))
6775 if (font->ntmFlags & NTM_PS_OPENTYPE)
6776 TM.tmPitchAndFamily |= TMPF_DEVICE;
6778 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6781 TM.tmCharSet = font->charset;
6783 font->potm->otmFiller = 0;
6784 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6785 font->potm->otmfsSelection = pOS2->fsSelection;
6786 font->potm->otmfsType = pOS2->fsType;
6787 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6788 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6789 font->potm->otmItalicAngle = 0; /* POST table */
6790 font->potm->otmEMSquare = ft_face->units_per_EM;
6791 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6792 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6793 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6794 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6795 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6796 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6797 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6798 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6799 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6800 font->potm->otmMacAscent = TM.tmAscent;
6801 font->potm->otmMacDescent = -TM.tmDescent;
6802 font->potm->otmMacLineGap = font->potm->otmLineGap;
6803 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6804 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6805 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6806 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6807 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6808 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6809 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6810 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6811 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6812 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6813 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6815 font->potm->otmsUnderscoreSize = 0;
6816 font->potm->otmsUnderscorePosition = 0;
6818 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6819 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6823 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6824 cp = (char*)font->potm + sizeof(*font->potm);
6825 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6826 strcpyW((WCHAR*)cp, family_nameW);
6828 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6829 strcpyW((WCHAR*)cp, style_nameW);
6831 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6832 strcpyW((WCHAR*)cp, face_nameW);
6834 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6835 strcpyW((WCHAR*)cp, full_nameW);
6839 HeapFree(GetProcessHeap(), 0, style_nameW);
6840 HeapFree(GetProcessHeap(), 0, family_nameW);
6841 HeapFree(GetProcessHeap(), 0, face_nameW);
6842 HeapFree(GetProcessHeap(), 0, full_nameW);
6846 /*************************************************************
6847 * freetype_GetGlyphOutline
6849 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6850 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6852 struct freetype_physdev *physdev = get_freetype_dev( dev );
6857 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6858 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6862 EnterCriticalSection( &freetype_cs );
6863 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6864 LeaveCriticalSection( &freetype_cs );
6868 /*************************************************************
6869 * freetype_GetTextMetrics
6871 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6873 struct freetype_physdev *physdev = get_freetype_dev( dev );
6878 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6879 return dev->funcs->pGetTextMetrics( dev, metrics );
6883 EnterCriticalSection( &freetype_cs );
6884 ret = get_text_metrics( physdev->font, metrics );
6885 LeaveCriticalSection( &freetype_cs );
6889 /*************************************************************
6890 * freetype_GetOutlineTextMetrics
6892 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6894 struct freetype_physdev *physdev = get_freetype_dev( dev );
6899 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6900 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6903 TRACE("font=%p\n", physdev->font);
6905 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6908 EnterCriticalSection( &freetype_cs );
6910 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6912 if(cbSize >= physdev->font->potm->otmSize)
6914 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6915 scale_outline_font_metrics(physdev->font, potm);
6917 ret = physdev->font->potm->otmSize;
6919 LeaveCriticalSection( &freetype_cs );
6923 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6925 HFONTLIST *hfontlist;
6926 child->font = alloc_font();
6927 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6928 if(!child->font->ft_face)
6930 free_font(child->font);
6935 child->font->font_desc = font->font_desc;
6936 child->font->ntmFlags = child->face->ntmFlags;
6937 child->font->orientation = font->orientation;
6938 child->font->scale_y = font->scale_y;
6939 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6940 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6941 child->font->name = strdupW(child->face->family->FamilyName);
6942 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6943 child->font->base_font = font;
6944 list_add_head(&child_font_list, &child->font->entry);
6945 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6949 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6952 CHILD_FONT *child_font;
6955 font = font->base_font;
6957 *linked_font = font;
6959 if((*glyph = get_glyph_index(font, c)))
6961 *glyph = get_GSUB_vert_glyph(font, *glyph);
6965 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6967 if(!child_font->font)
6968 if(!load_child_font(font, child_font))
6971 if(!child_font->font->ft_face)
6973 g = get_glyph_index(child_font->font, c);
6974 g = get_GSUB_vert_glyph(child_font->font, g);
6978 *linked_font = child_font->font;
6985 /*************************************************************
6986 * freetype_GetCharWidth
6988 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6990 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6993 FT_UInt glyph_index;
6994 GdiFont *linked_font;
6995 struct freetype_physdev *physdev = get_freetype_dev( dev );
6999 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7000 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7003 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7006 EnterCriticalSection( &freetype_cs );
7007 for(c = firstChar; c <= lastChar; c++) {
7008 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7009 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7010 &gm, 0, NULL, &identity);
7011 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
7013 LeaveCriticalSection( &freetype_cs );
7017 /*************************************************************
7018 * freetype_GetCharABCWidths
7020 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7022 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7025 FT_UInt glyph_index;
7026 GdiFont *linked_font;
7027 struct freetype_physdev *physdev = get_freetype_dev( dev );
7031 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7032 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7035 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7038 EnterCriticalSection( &freetype_cs );
7040 for(c = firstChar; c <= lastChar; c++) {
7041 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7042 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7043 &gm, 0, NULL, &identity);
7044 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
7045 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
7046 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
7047 FONT_GM(linked_font,glyph_index)->bbx;
7049 LeaveCriticalSection( &freetype_cs );
7053 /*************************************************************
7054 * freetype_GetCharABCWidthsI
7056 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7058 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7061 FT_UInt glyph_index;
7062 GdiFont *linked_font;
7063 struct freetype_physdev *physdev = get_freetype_dev( dev );
7067 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7068 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7071 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7075 EnterCriticalSection( &freetype_cs );
7077 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
7079 for(c = firstChar; c < firstChar+count; c++) {
7080 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
7081 &gm, 0, NULL, &identity);
7082 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
7083 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
7084 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
7085 - FONT_GM(linked_font,c)->bbx;
7088 for(c = 0; c < count; c++) {
7089 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
7090 &gm, 0, NULL, &identity);
7091 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
7092 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
7093 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
7094 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
7097 LeaveCriticalSection( &freetype_cs );
7101 /*************************************************************
7102 * freetype_GetTextExtentExPoint
7104 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7105 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7107 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7112 FT_UInt glyph_index;
7113 GdiFont *linked_font;
7114 struct freetype_physdev *physdev = get_freetype_dev( dev );
7118 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7119 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7122 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7125 EnterCriticalSection( &freetype_cs );
7128 get_text_metrics( physdev->font, &tm );
7129 size->cy = tm.tmHeight;
7131 for(idx = 0; idx < count; idx++) {
7132 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7133 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7134 &gm, 0, NULL, &identity);
7135 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7137 if (! pnfit || ext <= max_ext) {
7147 LeaveCriticalSection( &freetype_cs );
7148 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7152 /*************************************************************
7153 * freetype_GetTextExtentExPointI
7155 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7156 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7158 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7163 struct freetype_physdev *physdev = get_freetype_dev( dev );
7167 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7168 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7171 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7174 EnterCriticalSection( &freetype_cs );
7177 get_text_metrics(physdev->font, &tm);
7178 size->cy = tm.tmHeight;
7180 for(idx = 0; idx < count; idx++) {
7181 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7182 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7184 if (! pnfit || ext <= max_ext) {
7194 LeaveCriticalSection( &freetype_cs );
7195 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7199 /*************************************************************
7200 * freetype_GetFontData
7202 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7204 struct freetype_physdev *physdev = get_freetype_dev( dev );
7208 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7209 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7212 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7213 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7214 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7216 return get_font_data( physdev->font, table, offset, buf, cbData );
7219 /*************************************************************
7220 * freetype_GetTextFace
7222 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7225 struct freetype_physdev *physdev = get_freetype_dev( dev );
7229 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7230 return dev->funcs->pGetTextFace( dev, count, str );
7233 n = strlenW(physdev->font->name) + 1;
7236 lstrcpynW(str, physdev->font->name, count);
7242 /*************************************************************
7243 * freetype_GetTextCharsetInfo
7245 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7247 struct freetype_physdev *physdev = get_freetype_dev( dev );
7251 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7252 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7254 if (fs) *fs = physdev->font->fs;
7255 return physdev->font->charset;
7258 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7260 GdiFont *font = dc->gdiFont, *linked_font;
7261 struct list *first_hfont;
7265 EnterCriticalSection( &freetype_cs );
7266 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7267 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7268 if(font == linked_font)
7269 *new_hfont = dc->hFont;
7272 first_hfont = list_head(&linked_font->hfontlist);
7273 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7275 LeaveCriticalSection( &freetype_cs );
7279 /* Retrieve a list of supported Unicode ranges for a given font.
7280 * Can be called with NULL gs to calculate the buffer size. Returns
7281 * the number of ranges found.
7283 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7285 DWORD num_ranges = 0;
7287 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7290 FT_ULong char_code, char_code_prev;
7293 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7295 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7296 face->num_glyphs, glyph_code, char_code);
7298 if (!glyph_code) return 0;
7302 gs->ranges[0].wcLow = (USHORT)char_code;
7303 gs->ranges[0].cGlyphs = 0;
7304 gs->cGlyphsSupported = 0;
7310 if (char_code < char_code_prev)
7312 ERR("expected increasing char code from FT_Get_Next_Char\n");
7315 if (char_code - char_code_prev > 1)
7320 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7321 gs->ranges[num_ranges - 1].cGlyphs = 1;
7322 gs->cGlyphsSupported++;
7327 gs->ranges[num_ranges - 1].cGlyphs++;
7328 gs->cGlyphsSupported++;
7330 char_code_prev = char_code;
7331 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7335 FIXME("encoding %u not supported\n", face->charmap->encoding);
7340 /*************************************************************
7341 * freetype_GetFontUnicodeRanges
7343 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7345 struct freetype_physdev *physdev = get_freetype_dev( dev );
7346 DWORD size, num_ranges;
7350 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7351 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7354 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7355 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7358 glyphset->cbThis = size;
7359 glyphset->cRanges = num_ranges;
7360 glyphset->flAccel = 0;
7365 /*************************************************************
7366 * freetype_FontIsLinked
7368 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7370 struct freetype_physdev *physdev = get_freetype_dev( dev );
7375 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7376 return dev->funcs->pFontIsLinked( dev );
7380 EnterCriticalSection( &freetype_cs );
7381 ret = !list_empty(&physdev->font->child_fonts);
7382 LeaveCriticalSection( &freetype_cs );
7386 static BOOL is_hinting_enabled(void)
7388 /* Use the >= 2.2.0 function if available */
7389 if(pFT_Get_TrueType_Engine_Type)
7391 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
7392 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
7394 #ifdef FT_DRIVER_HAS_HINTER
7399 /* otherwise if we've been compiled with < 2.2.0 headers
7400 use the internal macro */
7401 mod = pFT_Get_Module(library, "truetype");
7402 if(mod && FT_DRIVER_HAS_HINTER(mod))
7410 static BOOL is_subpixel_rendering_enabled( void )
7412 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7413 return pFT_Library_SetLcdFilter &&
7414 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7420 /*************************************************************************
7421 * GetRasterizerCaps (GDI32.@)
7423 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7425 static int hinting = -1;
7426 static int subpixel = -1;
7430 hinting = is_hinting_enabled();
7431 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7434 if ( subpixel == -1 )
7436 subpixel = is_subpixel_rendering_enabled();
7437 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7440 lprs->nSize = sizeof(RASTERIZER_STATUS);
7441 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7443 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7444 lprs->nLanguageID = 0;
7448 /*************************************************************
7449 * freetype_GdiRealizationInfo
7451 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7453 struct freetype_physdev *physdev = get_freetype_dev( dev );
7454 realization_info_t *info = ptr;
7458 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7459 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7462 FIXME("(%p, %p): stub!\n", physdev->font, info);
7465 if(FT_IS_SCALABLE(physdev->font->ft_face))
7468 info->cache_num = physdev->font->cache_num;
7469 info->unknown2 = -1;
7473 /*************************************************************************
7474 * Kerning support for TrueType fonts
7476 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7478 struct TT_kern_table
7484 struct TT_kern_subtable
7493 USHORT horizontal : 1;
7495 USHORT cross_stream: 1;
7496 USHORT override : 1;
7497 USHORT reserved1 : 4;
7503 struct TT_format0_kern_subtable
7507 USHORT entrySelector;
7518 static DWORD parse_format0_kern_subtable(GdiFont *font,
7519 const struct TT_format0_kern_subtable *tt_f0_ks,
7520 const USHORT *glyph_to_char,
7521 KERNINGPAIR *kern_pair, DWORD cPairs)
7524 const struct TT_kern_pair *tt_kern_pair;
7526 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7528 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7530 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7531 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7532 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7534 if (!kern_pair || !cPairs)
7537 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7539 nPairs = min(nPairs, cPairs);
7541 for (i = 0; i < nPairs; i++)
7543 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7544 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7545 /* this algorithm appears to better match what Windows does */
7546 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7547 if (kern_pair->iKernAmount < 0)
7549 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7550 kern_pair->iKernAmount -= font->ppem;
7552 else if (kern_pair->iKernAmount > 0)
7554 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7555 kern_pair->iKernAmount += font->ppem;
7557 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7559 TRACE("left %u right %u value %d\n",
7560 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7564 TRACE("copied %u entries\n", nPairs);
7568 /*************************************************************
7569 * freetype_GetKerningPairs
7571 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7575 const struct TT_kern_table *tt_kern_table;
7576 const struct TT_kern_subtable *tt_kern_subtable;
7578 USHORT *glyph_to_char;
7580 struct freetype_physdev *physdev = get_freetype_dev( dev );
7582 if (!(font = physdev->font))
7584 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7585 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7589 EnterCriticalSection( &freetype_cs );
7590 if (font->total_kern_pairs != (DWORD)-1)
7592 if (cPairs && kern_pair)
7594 cPairs = min(cPairs, font->total_kern_pairs);
7595 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7597 else cPairs = font->total_kern_pairs;
7599 LeaveCriticalSection( &freetype_cs );
7603 font->total_kern_pairs = 0;
7605 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7607 if (length == GDI_ERROR)
7609 TRACE("no kerning data in the font\n");
7610 LeaveCriticalSection( &freetype_cs );
7614 buf = HeapAlloc(GetProcessHeap(), 0, length);
7617 WARN("Out of memory\n");
7618 LeaveCriticalSection( &freetype_cs );
7622 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7624 /* build a glyph index to char code map */
7625 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7628 WARN("Out of memory allocating a glyph index to char code map\n");
7629 HeapFree(GetProcessHeap(), 0, buf);
7630 LeaveCriticalSection( &freetype_cs );
7634 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7640 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7642 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7643 font->ft_face->num_glyphs, glyph_code, char_code);
7647 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7649 /* FIXME: This doesn't match what Windows does: it does some fancy
7650 * things with duplicate glyph index to char code mappings, while
7651 * we just avoid overriding existing entries.
7653 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7654 glyph_to_char[glyph_code] = (USHORT)char_code;
7656 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7663 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7664 for (n = 0; n <= 65535; n++)
7665 glyph_to_char[n] = (USHORT)n;
7668 tt_kern_table = buf;
7669 nTables = GET_BE_WORD(tt_kern_table->nTables);
7670 TRACE("version %u, nTables %u\n",
7671 GET_BE_WORD(tt_kern_table->version), nTables);
7673 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7675 for (i = 0; i < nTables; i++)
7677 struct TT_kern_subtable tt_kern_subtable_copy;
7679 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7680 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7681 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7683 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7684 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7685 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7687 /* According to the TrueType specification this is the only format
7688 * that will be properly interpreted by Windows and OS/2
7690 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7692 DWORD new_chunk, old_total = font->total_kern_pairs;
7694 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7695 glyph_to_char, NULL, 0);
7696 font->total_kern_pairs += new_chunk;
7698 if (!font->kern_pairs)
7699 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7700 font->total_kern_pairs * sizeof(*font->kern_pairs));
7702 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7703 font->total_kern_pairs * sizeof(*font->kern_pairs));
7705 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7706 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7709 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7711 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7714 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7715 HeapFree(GetProcessHeap(), 0, buf);
7717 if (cPairs && kern_pair)
7719 cPairs = min(cPairs, font->total_kern_pairs);
7720 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7722 else cPairs = font->total_kern_pairs;
7724 LeaveCriticalSection( &freetype_cs );
7728 static const struct gdi_dc_funcs freetype_funcs =
7730 NULL, /* pAbortDoc */
7731 NULL, /* pAbortPath */
7732 NULL, /* pAlphaBlend */
7733 NULL, /* pAngleArc */
7736 NULL, /* pBeginPath */
7737 NULL, /* pBlendImage */
7739 NULL, /* pCloseFigure */
7740 NULL, /* pCreateCompatibleDC */
7741 freetype_CreateDC, /* pCreateDC */
7742 freetype_DeleteDC, /* pDeleteDC */
7743 NULL, /* pDeleteObject */
7744 NULL, /* pDeviceCapabilities */
7745 NULL, /* pEllipse */
7747 NULL, /* pEndPage */
7748 NULL, /* pEndPath */
7749 freetype_EnumFonts, /* pEnumFonts */
7750 NULL, /* pEnumICMProfiles */
7751 NULL, /* pExcludeClipRect */
7752 NULL, /* pExtDeviceMode */
7753 NULL, /* pExtEscape */
7754 NULL, /* pExtFloodFill */
7755 NULL, /* pExtSelectClipRgn */
7756 NULL, /* pExtTextOut */
7757 NULL, /* pFillPath */
7758 NULL, /* pFillRgn */
7759 NULL, /* pFlattenPath */
7760 freetype_FontIsLinked, /* pFontIsLinked */
7761 NULL, /* pFrameRgn */
7762 NULL, /* pGdiComment */
7763 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7764 NULL, /* pGetBoundsRect */
7765 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7766 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7767 freetype_GetCharWidth, /* pGetCharWidth */
7768 NULL, /* pGetDeviceCaps */
7769 NULL, /* pGetDeviceGammaRamp */
7770 freetype_GetFontData, /* pGetFontData */
7771 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7772 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7773 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7774 NULL, /* pGetICMProfile */
7775 NULL, /* pGetImage */
7776 freetype_GetKerningPairs, /* pGetKerningPairs */
7777 NULL, /* pGetNearestColor */
7778 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7779 NULL, /* pGetPixel */
7780 NULL, /* pGetSystemPaletteEntries */
7781 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7782 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7783 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7784 freetype_GetTextFace, /* pGetTextFace */
7785 freetype_GetTextMetrics, /* pGetTextMetrics */
7786 NULL, /* pGradientFill */
7787 NULL, /* pIntersectClipRect */
7788 NULL, /* pInvertRgn */
7790 NULL, /* pModifyWorldTransform */
7792 NULL, /* pOffsetClipRgn */
7793 NULL, /* pOffsetViewportOrg */
7794 NULL, /* pOffsetWindowOrg */
7795 NULL, /* pPaintRgn */
7798 NULL, /* pPolyBezier */
7799 NULL, /* pPolyBezierTo */
7800 NULL, /* pPolyDraw */
7801 NULL, /* pPolyPolygon */
7802 NULL, /* pPolyPolyline */
7803 NULL, /* pPolygon */
7804 NULL, /* pPolyline */
7805 NULL, /* pPolylineTo */
7806 NULL, /* pPutImage */
7807 NULL, /* pRealizeDefaultPalette */
7808 NULL, /* pRealizePalette */
7809 NULL, /* pRectangle */
7810 NULL, /* pResetDC */
7811 NULL, /* pRestoreDC */
7812 NULL, /* pRoundRect */
7814 NULL, /* pScaleViewportExt */
7815 NULL, /* pScaleWindowExt */
7816 NULL, /* pSelectBitmap */
7817 NULL, /* pSelectBrush */
7818 NULL, /* pSelectClipPath */
7819 freetype_SelectFont, /* pSelectFont */
7820 NULL, /* pSelectPalette */
7821 NULL, /* pSelectPen */
7822 NULL, /* pSetArcDirection */
7823 NULL, /* pSetBkColor */
7824 NULL, /* pSetBkMode */
7825 NULL, /* pSetDCBrushColor */
7826 NULL, /* pSetDCPenColor */
7827 NULL, /* pSetDIBColorTable */
7828 NULL, /* pSetDIBitsToDevice */
7829 NULL, /* pSetDeviceClipping */
7830 NULL, /* pSetDeviceGammaRamp */
7831 NULL, /* pSetLayout */
7832 NULL, /* pSetMapMode */
7833 NULL, /* pSetMapperFlags */
7834 NULL, /* pSetPixel */
7835 NULL, /* pSetPolyFillMode */
7836 NULL, /* pSetROP2 */
7837 NULL, /* pSetRelAbs */
7838 NULL, /* pSetStretchBltMode */
7839 NULL, /* pSetTextAlign */
7840 NULL, /* pSetTextCharacterExtra */
7841 NULL, /* pSetTextColor */
7842 NULL, /* pSetTextJustification */
7843 NULL, /* pSetViewportExt */
7844 NULL, /* pSetViewportOrg */
7845 NULL, /* pSetWindowExt */
7846 NULL, /* pSetWindowOrg */
7847 NULL, /* pSetWorldTransform */
7848 NULL, /* pStartDoc */
7849 NULL, /* pStartPage */
7850 NULL, /* pStretchBlt */
7851 NULL, /* pStretchDIBits */
7852 NULL, /* pStrokeAndFillPath */
7853 NULL, /* pStrokePath */
7854 NULL, /* pUnrealizePalette */
7855 NULL, /* pWidenPath */
7856 NULL, /* wine_get_wgl_driver */
7857 GDI_PRIORITY_FONT_DRV /* priority */
7860 #else /* HAVE_FREETYPE */
7862 /*************************************************************************/
7864 BOOL WineEngInit(void)
7868 BOOL WineEngDestroyFontInstance(HFONT hfont)
7873 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7875 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7879 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7881 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7885 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7887 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7891 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7892 LPCWSTR font_file, LPCWSTR font_path )
7898 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7903 /*************************************************************************
7904 * GetRasterizerCaps (GDI32.@)
7906 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7908 lprs->nSize = sizeof(RASTERIZER_STATUS);
7910 lprs->nLanguageID = 0;
7914 #endif /* HAVE_FREETYPE */