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;
353 const WCHAR *font_name;
358 struct enum_charset_element {
361 WCHAR name[LF_FACESIZE];
364 struct enum_charset_list {
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 struct freetype_physdev
384 struct gdi_physdev dev;
388 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
390 return (struct freetype_physdev *)dev;
393 static const struct gdi_dc_funcs freetype_funcs;
395 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR * const SystemFontValues[] = {
422 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
428 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
438 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
439 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR *default_serif_list[] =
450 bitstream_vera_serif,
454 static const WCHAR *default_fixed_list[] =
458 bitstream_vera_sans_mono,
462 static const WCHAR *default_sans_list[] =
475 typedef struct tagFontSubst {
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
487 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
488 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
489 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
490 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
491 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
492 static const WCHAR face_size_value[] = {'S','i','z','e',0};
493 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
494 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
495 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
496 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
497 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
510 static struct list mappings_list = LIST_INIT( mappings_list );
512 static CRITICAL_SECTION freetype_cs;
513 static CRITICAL_SECTION_DEBUG critsect_debug =
516 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
517 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
519 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
521 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
523 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
524 static BOOL use_default_fallback = FALSE;
526 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
527 static BOOL get_outline_text_metrics(GdiFont *font);
528 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
530 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
531 'W','i','n','d','o','w','s',' ','N','T','\\',
532 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
533 'S','y','s','t','e','m','L','i','n','k',0};
535 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
536 'F','o','n','t','L','i','n','k','\\',
537 'S','y','s','t','e','m','L','i','n','k',0};
539 /****************************************
540 * Notes on .fon files
542 * The fonts System, FixedSys and Terminal are special. There are typically multiple
543 * versions installed for different resolutions and codepages. Windows stores which one to use
544 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
546 * FIXEDFON.FON FixedSys
548 * OEMFONT.FON Terminal
549 * LogPixels Current dpi set by the display control panel applet
550 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
551 * also has a LogPixels value that appears to mirror this)
553 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
554 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
555 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
556 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
557 * so that makes sense.
559 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
560 * to be mapped into the registry on Windows 2000 at least).
563 * ega80woa.fon=ega80850.fon
564 * ega40woa.fon=ega40850.fon
565 * cga80woa.fon=cga80850.fon
566 * cga40woa.fon=cga40850.fon
569 /* These are all structures needed for the GSUB table */
571 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
572 #define TATEGAKI_LOWER_BOUND 0x02F1
588 GSUB_ScriptRecord ScriptRecord[1];
594 } GSUB_LangSysRecord;
599 GSUB_LangSysRecord LangSysRecord[1];
603 WORD LookupOrder; /* Reserved */
604 WORD ReqFeatureIndex;
606 WORD FeatureIndex[1];
612 } GSUB_FeatureRecord;
616 GSUB_FeatureRecord FeatureRecord[1];
620 WORD FeatureParams; /* Reserved */
622 WORD LookupListIndex[1];
641 } GSUB_CoverageFormat1;
646 WORD StartCoverageIndex;
652 GSUB_RangeRecord RangeRecord[1];
653 } GSUB_CoverageFormat2;
656 WORD SubstFormat; /* = 1 */
659 } GSUB_SingleSubstFormat1;
662 WORD SubstFormat; /* = 2 */
666 }GSUB_SingleSubstFormat2;
668 #ifdef HAVE_CARBON_CARBON_H
669 static char *find_cache_dir(void)
673 static char cached_path[MAX_PATH];
674 static const char *wine = "/Wine", *fonts = "/Fonts";
676 if(*cached_path) return cached_path;
678 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
681 WARN("can't create cached data folder\n");
684 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
687 WARN("can't create cached data path\n");
691 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
693 ERR("Could not create full path\n");
697 strcat(cached_path, wine);
699 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
701 WARN("Couldn't mkdir %s\n", cached_path);
705 strcat(cached_path, fonts);
706 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
708 WARN("Couldn't mkdir %s\n", cached_path);
715 /******************************************************************
718 * Extracts individual TrueType font files from a Mac suitcase font
719 * and saves them into the user's caches directory (see
721 * Returns a NULL terminated array of filenames.
723 * We do this because they are apps that try to read ttf files
724 * themselves and they don't like Mac suitcase files.
726 static char **expand_mac_font(const char *path)
733 const char *filename;
737 unsigned int size, max_size;
740 TRACE("path %s\n", path);
742 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
745 WARN("failed to get ref\n");
749 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
752 TRACE("no data fork, so trying resource fork\n");
753 res_ref = FSOpenResFile(&ref, fsRdPerm);
756 TRACE("unable to open resource fork\n");
763 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
766 CloseResFile(res_ref);
770 out_dir = find_cache_dir();
772 filename = strrchr(path, '/');
773 if(!filename) filename = path;
776 /* output filename has the form out_dir/filename_%04x.ttf */
777 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
784 unsigned short *num_faces_ptr, num_faces, face;
787 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
789 fond = Get1IndResource(fond_res, idx);
791 TRACE("got fond resource %d\n", idx);
794 fam_rec = *(FamRec**)fond;
795 num_faces_ptr = (unsigned short *)(fam_rec + 1);
796 num_faces = GET_BE_WORD(*num_faces_ptr);
798 assoc = (AsscEntry*)(num_faces_ptr + 1);
799 TRACE("num faces %04x\n", num_faces);
800 for(face = 0; face < num_faces; face++, assoc++)
803 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
804 unsigned short size, font_id;
807 size = GET_BE_WORD(assoc->fontSize);
808 font_id = GET_BE_WORD(assoc->fontID);
811 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
815 TRACE("trying to load sfnt id %04x\n", font_id);
816 sfnt = GetResource(sfnt_res, font_id);
819 TRACE("can't get sfnt resource %04x\n", font_id);
823 output = HeapAlloc(GetProcessHeap(), 0, output_len);
828 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
830 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
831 if(fd != -1 || errno == EEXIST)
835 unsigned char *sfnt_data;
838 sfnt_data = *(unsigned char**)sfnt;
839 write(fd, sfnt_data, GetHandleSize(sfnt));
843 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
846 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
848 ret.array[ret.size++] = output;
852 WARN("unable to create %s\n", output);
853 HeapFree(GetProcessHeap(), 0, output);
856 ReleaseResource(sfnt);
859 ReleaseResource(fond);
862 CloseResFile(res_ref);
867 #endif /* HAVE_CARBON_CARBON_H */
869 static inline BOOL is_win9x(void)
871 return GetVersion() & 0x80000000;
874 This function builds an FT_Fixed from a double. It fails if the absolute
875 value of the float number is greater than 32768.
877 static inline FT_Fixed FT_FixedFromFloat(double f)
883 This function builds an FT_Fixed from a FIXED. It simply put f.value
884 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
886 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
888 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
892 static const struct list *get_face_list_from_family(const Family *family)
894 if (!list_empty(&family->faces))
895 return &family->faces;
897 return family->replacement;
900 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
905 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
906 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
908 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
909 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
911 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
913 const struct list *face_list;
914 if(face_name && strcmpiW(face_name, family->FamilyName))
916 face_list = get_face_list_from_family(family);
917 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
921 file = strrchr(face->file, '/');
926 if(!strcasecmp(file, file_nameA))
928 HeapFree(GetProcessHeap(), 0, file_nameA);
933 HeapFree(GetProcessHeap(), 0, file_nameA);
937 static Family *find_family_from_name(const WCHAR *name)
941 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
943 if(!strcmpiW(family->FamilyName, name))
950 static Family *find_family_from_any_name(const WCHAR *name)
954 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
956 if(!strcmpiW(family->FamilyName, name))
958 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
965 static void DumpSubstList(void)
969 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
971 if(psub->from.charset != -1 || psub->to.charset != -1)
972 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
973 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
975 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
976 debugstr_w(psub->to.name));
981 static LPWSTR strdupW(LPCWSTR p)
984 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
985 ret = HeapAlloc(GetProcessHeap(), 0, len);
990 static LPSTR strdupA(LPCSTR p)
993 DWORD len = (strlen(p) + 1);
994 ret = HeapAlloc(GetProcessHeap(), 0, len);
999 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1004 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1006 if(!strcmpiW(element->from.name, from_name) &&
1007 (element->from.charset == from_charset ||
1008 element->from.charset == -1))
1015 #define ADD_FONT_SUBST_FORCE 1
1017 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1019 FontSubst *from_exist, *to_exist;
1021 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1023 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1025 list_remove(&from_exist->entry);
1026 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1028 HeapFree(GetProcessHeap(), 0, from_exist);
1034 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1038 HeapFree(GetProcessHeap(), 0, subst->to.name);
1039 subst->to.name = strdupW(to_exist->to.name);
1042 list_add_tail(subst_list, &subst->entry);
1047 HeapFree(GetProcessHeap(), 0, subst->from.name);
1048 HeapFree(GetProcessHeap(), 0, subst->to.name);
1049 HeapFree(GetProcessHeap(), 0, subst);
1053 static WCHAR *towstr(UINT cp, const char *str)
1058 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1059 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1060 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1064 static void split_subst_info(NameCs *nc, LPSTR str)
1066 CHAR *p = strrchr(str, ',');
1070 nc->charset = strtol(p+1, NULL, 10);
1073 nc->name = towstr(CP_ACP, str);
1076 static void LoadSubstList(void)
1080 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1084 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1085 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1086 &hkey) == ERROR_SUCCESS) {
1088 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1089 &valuelen, &datalen, NULL, NULL);
1091 valuelen++; /* returned value doesn't include room for '\0' */
1092 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1093 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1097 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1098 &dlen) == ERROR_SUCCESS) {
1099 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1101 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1102 split_subst_info(&psub->from, value);
1103 split_subst_info(&psub->to, data);
1105 /* Win 2000 doesn't allow mapping between different charsets
1106 or mapping of DEFAULT_CHARSET */
1107 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1108 psub->to.charset == DEFAULT_CHARSET) {
1109 HeapFree(GetProcessHeap(), 0, psub->to.name);
1110 HeapFree(GetProcessHeap(), 0, psub->from.name);
1111 HeapFree(GetProcessHeap(), 0, psub);
1113 add_font_subst(&font_subst_list, psub, 0);
1115 /* reset dlen and vlen */
1119 HeapFree(GetProcessHeap(), 0, data);
1120 HeapFree(GetProcessHeap(), 0, value);
1126 /*****************************************************************
1127 * get_name_table_entry
1129 * Supply the platform, encoding, language and name ids in req
1130 * and if the name exists the function will fill in the string
1131 * and string_len members. The string is owned by FreeType so
1132 * don't free it. Returns TRUE if the name is found else FALSE.
1134 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1137 FT_UInt num_names, name_index;
1139 if(FT_IS_SFNT(ft_face))
1141 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1143 for(name_index = 0; name_index < num_names; name_index++)
1145 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1147 if((name.platform_id == req->platform_id) &&
1148 (name.encoding_id == req->encoding_id) &&
1149 (name.language_id == req->language_id) &&
1150 (name.name_id == req->name_id))
1152 req->string = name.string;
1153 req->string_len = name.string_len;
1160 req->string_len = 0;
1164 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1169 name.platform_id = TT_PLATFORM_MICROSOFT;
1170 name.encoding_id = TT_MS_ID_UNICODE_CS;
1171 name.language_id = language_id;
1172 name.name_id = name_id;
1174 if(get_name_table_entry(ft_face, &name))
1178 /* String is not nul terminated and string_len is a byte length. */
1179 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1180 for(i = 0; i < name.string_len / 2; i++)
1182 WORD *tmp = (WORD *)&name.string[i * 2];
1183 ret[i] = GET_BE_WORD(*tmp);
1186 TRACE("Got localised name %s\n", debugstr_w(ret));
1192 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1194 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1195 if (f1->scalable) return TRUE;
1196 if (f2->size.y_ppem != f2->size.y_ppem) return FALSE;
1197 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1200 static inline void free_face( Face *face )
1202 HeapFree( GetProcessHeap(), 0, face->file );
1203 HeapFree( GetProcessHeap(), 0, face->StyleName );
1204 HeapFree( GetProcessHeap(), 0, face->FullName );
1205 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1206 HeapFree( GetProcessHeap(), 0, face );
1209 static inline void free_family( Family *family )
1211 Face *face, *cursor2;
1213 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1215 list_remove( &face->entry );
1218 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1219 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1220 HeapFree( GetProcessHeap(), 0, family );
1223 static inline int style_order(const Face *face)
1225 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1233 case NTM_BOLD | NTM_ITALIC:
1236 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1237 debugstr_w(face->family->FamilyName),
1238 debugstr_w(face->StyleName),
1244 static BOOL insert_face_in_family_list( Face *face, Family *family )
1248 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1250 if (faces_equal( face, cursor ))
1252 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1253 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1254 cursor->font_version, face->font_version);
1256 if (face->font_version <= cursor->font_version)
1258 TRACE("Original font is newer so skipping this one\n");
1263 TRACE("Replacing original with this one\n");
1264 list_add_before( &cursor->entry, &face->entry );
1265 face->family = family;
1266 list_remove( &cursor->entry);
1267 free_face( cursor );
1272 if (style_order( face ) < style_order( cursor )) break;
1275 list_add_before( &cursor->entry, &face->entry );
1276 face->family = family;
1280 /****************************************************************
1281 * NB This function stores the ptrs to the strings to save copying.
1282 * Don't free them after calling.
1284 static Family *create_family( WCHAR *name, WCHAR *english_name )
1286 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1287 family->FamilyName = name;
1288 family->EnglishName = english_name;
1289 list_init( &family->faces );
1290 family->replacement = &family->faces;
1295 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1298 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1299 if(r != ERROR_SUCCESS) return r;
1300 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1301 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1304 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1306 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1309 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1312 DWORD num_strikes, max_strike_key_len;
1314 /* If we have a File Name key then this is a real font, not just the parent
1315 key of a bunch of non-scalable strikes */
1316 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1319 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1320 face->cached_enum_data = NULL;
1322 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1323 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1325 face->StyleName = strdupW(face_name);
1327 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1329 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1330 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1331 face->FullName = fullName;
1334 face->FullName = NULL;
1336 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1337 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1338 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1339 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1341 needed = sizeof(face->fs);
1342 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1344 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1346 face->scalable = TRUE;
1347 memset(&face->size, 0, sizeof(face->size));
1351 face->scalable = FALSE;
1352 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1353 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1354 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1355 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1356 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1358 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1359 face->size.height, face->size.width, face->size.size >> 6,
1360 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1363 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1364 face->fs.fsCsb[0], face->fs.fsCsb[1],
1365 face->fs.fsUsb[0], face->fs.fsUsb[1],
1366 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1368 insert_face_in_family_list(face, family);
1370 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1373 /* do we have any bitmap strikes? */
1374 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1375 NULL, NULL, NULL, NULL);
1376 if(num_strikes != 0)
1378 WCHAR strike_name[10];
1379 DWORD strike_index = 0;
1381 needed = sizeof(strike_name) / sizeof(WCHAR);
1382 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1383 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1386 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1387 load_face(hkey_strike, face_name, family);
1388 RegCloseKey(hkey_strike);
1389 needed = sizeof(strike_name) / sizeof(WCHAR);
1394 static void load_font_list_from_cache(HKEY hkey_font_cache)
1396 DWORD max_family_key_len, size;
1398 DWORD family_index = 0;
1402 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1403 NULL, NULL, NULL, NULL);
1404 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1406 size = max_family_key_len + 1;
1407 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1408 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1410 WCHAR *english_family = NULL;
1411 DWORD face_index = 0;
1413 DWORD max_face_key_len;
1415 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1416 TRACE("opened family key %s\n", debugstr_w(family_name));
1417 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1419 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1420 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1423 family = create_family(strdupW(family_name), english_family);
1424 list_add_tail(&font_list, &family->entry);
1428 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1429 subst->from.name = strdupW(english_family);
1430 subst->from.charset = -1;
1431 subst->to.name = strdupW(family_name);
1432 subst->to.charset = -1;
1433 add_font_subst(&font_subst_list, subst, 0);
1436 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1437 NULL, NULL, NULL, NULL);
1439 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1440 size = max_face_key_len + 1;
1441 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1442 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1446 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1447 load_face(hkey_face, face_name, family);
1448 RegCloseKey(hkey_face);
1449 size = max_face_key_len + 1;
1451 HeapFree(GetProcessHeap(), 0, face_name);
1452 RegCloseKey(hkey_family);
1453 size = max_family_key_len + 1;
1456 HeapFree(GetProcessHeap(), 0, family_name);
1459 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1462 HKEY hkey_wine_fonts;
1464 /* We don't want to create the fonts key as volatile, so open this first */
1465 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1466 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1467 if(ret != ERROR_SUCCESS)
1469 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1473 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1474 KEY_ALL_ACCESS, NULL, hkey, disposition);
1475 RegCloseKey(hkey_wine_fonts);
1479 static void add_face_to_cache(Face *face)
1481 HKEY hkey_font_cache, hkey_family, hkey_face;
1482 WCHAR *face_key_name;
1484 create_font_cache_key(&hkey_font_cache, NULL);
1486 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1487 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1488 if(face->family->EnglishName)
1489 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1490 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1493 face_key_name = face->StyleName;
1496 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1497 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1498 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1500 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1503 HeapFree(GetProcessHeap(), 0, face_key_name);
1505 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1507 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1508 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1510 reg_save_dword(hkey_face, face_index_value, face->face_index);
1511 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1512 reg_save_dword(hkey_face, face_version_value, face->font_version);
1513 reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1515 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1519 reg_save_dword(hkey_face, face_height_value, face->size.height);
1520 reg_save_dword(hkey_face, face_width_value, face->size.width);
1521 reg_save_dword(hkey_face, face_size_value, face->size.size);
1522 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1523 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1524 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1526 RegCloseKey(hkey_face);
1527 RegCloseKey(hkey_family);
1528 RegCloseKey(hkey_font_cache);
1531 static WCHAR *prepend_at(WCHAR *family)
1538 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1540 strcpyW(str + 1, family);
1541 HeapFree(GetProcessHeap(), 0, family);
1545 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1547 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1548 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1550 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1556 else if (!strcmpiW( *name, *english ))
1558 HeapFree( GetProcessHeap(), 0, *english );
1564 *name = prepend_at( *name );
1565 *english = prepend_at( *english );
1569 static Family *get_family( FT_Face ft_face, BOOL vertical )
1572 WCHAR *name, *english_name;
1574 get_family_names( ft_face, &name, &english_name, vertical );
1576 family = find_family_from_name( name );
1580 family = create_family( name, english_name );
1581 list_add_tail( &font_list, &family->entry );
1585 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1586 subst->from.name = strdupW( english_name );
1587 subst->from.charset = -1;
1588 subst->to.name = strdupW( name );
1589 subst->to.charset = -1;
1590 add_font_subst( &font_subst_list, subst, 0 );
1595 HeapFree( GetProcessHeap(), 0, name );
1596 HeapFree( GetProcessHeap(), 0, english_name );
1602 static inline FT_Fixed get_font_version( FT_Face ft_face )
1604 FT_Fixed version = 0;
1607 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1608 if (header) version = header->Font_Revision;
1613 static inline DWORD get_ntm_flags( FT_Face ft_face )
1616 FT_ULong table_size = 0;
1618 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1619 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1620 if (flags == 0) flags = NTM_REGULAR;
1622 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1623 flags |= NTM_PS_OPENTYPE;
1628 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1630 int internal_leading = 0;
1631 FT_WinFNT_HeaderRec winfnt_header;
1633 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1634 internal_leading = winfnt_header.internal_leading;
1636 return internal_leading;
1639 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1644 FT_WinFNT_HeaderRec winfnt_header;
1647 memset( fs, 0, sizeof(*fs) );
1649 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1652 fs->fsUsb[0] = os2->ulUnicodeRange1;
1653 fs->fsUsb[1] = os2->ulUnicodeRange2;
1654 fs->fsUsb[2] = os2->ulUnicodeRange3;
1655 fs->fsUsb[3] = os2->ulUnicodeRange4;
1657 if (os2->version == 0)
1659 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1660 fs->fsCsb[0] = FS_LATIN1;
1662 fs->fsCsb[0] = FS_SYMBOL;
1666 fs->fsCsb[0] = os2->ulCodePageRange1;
1667 fs->fsCsb[1] = os2->ulCodePageRange2;
1672 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1674 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1675 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1676 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1681 if (fs->fsCsb[0] == 0)
1683 /* let's see if we can find any interesting cmaps */
1684 for (i = 0; i < ft_face->num_charmaps; i++)
1686 switch (ft_face->charmaps[i]->encoding)
1688 case FT_ENCODING_UNICODE:
1689 case FT_ENCODING_APPLE_ROMAN:
1690 fs->fsCsb[0] |= FS_LATIN1;
1692 case FT_ENCODING_MS_SYMBOL:
1693 fs->fsCsb[0] |= FS_SYMBOL;
1702 #define ADDFONT_EXTERNAL_FONT 0x01
1703 #define ADDFONT_FORCE_BITMAP 0x02
1704 #define ADDFONT_ADD_TO_CACHE 0x04
1706 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1707 DWORD flags, BOOL vertical )
1709 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1710 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1712 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1713 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1716 face->file = strdupA( file );
1717 face->font_data_ptr = NULL;
1718 face->font_data_size = 0;
1723 face->font_data_ptr = font_data_ptr;
1724 face->font_data_size = font_data_size;
1727 face->face_index = face_index;
1728 get_fontsig( ft_face, &face->fs );
1729 face->ntmFlags = get_ntm_flags( ft_face );
1730 face->font_version = get_font_version( ft_face );
1732 if (FT_IS_SCALABLE( ft_face ))
1734 memset( &face->size, 0, sizeof(face->size) );
1735 face->scalable = TRUE;
1739 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1740 size->height, size->width, size->size >> 6,
1741 size->x_ppem >> 6, size->y_ppem >> 6);
1742 face->size.height = size->height;
1743 face->size.width = size->width;
1744 face->size.size = size->size;
1745 face->size.x_ppem = size->x_ppem;
1746 face->size.y_ppem = size->y_ppem;
1747 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1748 face->scalable = FALSE;
1751 face->vertical = vertical;
1752 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1753 face->family = NULL;
1754 face->cached_enum_data = NULL;
1756 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1757 face->fs.fsCsb[0], face->fs.fsCsb[1],
1758 face->fs.fsUsb[0], face->fs.fsUsb[1],
1759 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1764 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1765 FT_Long face_index, DWORD flags, BOOL vertical)
1770 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1771 family = get_family( ft_face, vertical );
1772 if (!insert_face_in_family_list( face, family ))
1778 if (flags & ADDFONT_ADD_TO_CACHE)
1779 add_face_to_cache( face );
1781 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1782 debugstr_w(face->StyleName));
1785 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1786 FT_Long face_index, BOOL allow_bitmap )
1794 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1795 err = pFT_New_Face(library, file, face_index, &ft_face);
1799 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1800 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1805 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1809 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1810 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1812 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1816 if (!FT_IS_SFNT( ft_face ))
1818 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1820 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1826 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1827 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1828 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1830 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1831 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1835 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1836 we don't want to load these. */
1837 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1841 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1843 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1849 if (!ft_face->family_name || !ft_face->style_name)
1851 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1857 pFT_Done_Face( ft_face );
1861 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1864 FT_Long face_index = 0, num_faces;
1867 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1868 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1870 #ifdef HAVE_CARBON_CARBON_H
1873 char **mac_list = expand_mac_font(file);
1876 BOOL had_one = FALSE;
1878 for(cursor = mac_list; *cursor; cursor++)
1881 AddFontToList(*cursor, NULL, 0, flags);
1882 HeapFree(GetProcessHeap(), 0, *cursor);
1884 HeapFree(GetProcessHeap(), 0, mac_list);
1889 #endif /* HAVE_CARBON_CARBON_H */
1892 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1893 if (!ft_face) return 0;
1895 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1897 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1898 pFT_Done_Face(ft_face);
1902 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1905 if (FT_HAS_VERTICAL(ft_face))
1907 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1911 num_faces = ft_face->num_faces;
1912 pFT_Done_Face(ft_face);
1913 } while(num_faces > ++face_index);
1917 static void DumpFontList(void)
1921 struct list *family_elem_ptr, *face_elem_ptr;
1923 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1924 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1925 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1926 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1927 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1928 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1930 TRACE(" %d", face->size.height);
1937 /***********************************************************
1938 * The replacement list is a way to map an entire font
1939 * family onto another family. For example adding
1941 * [HKCU\Software\Wine\Fonts\Replacements]
1942 * "Wingdings"="Winedings"
1944 * would enumerate the Winedings font both as Winedings and
1945 * Wingdings. However if a real Wingdings font is present the
1946 * replacement does not take place.
1949 static void LoadReplaceList(void)
1952 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1957 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1958 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1960 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1961 &valuelen, &datalen, NULL, NULL);
1963 valuelen++; /* returned value doesn't include room for '\0' */
1964 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1965 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1969 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1970 &dlen) == ERROR_SUCCESS) {
1971 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1972 /* "NewName"="Oldname" */
1973 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1975 if(!find_family_from_any_name(value))
1977 Family * const family = find_family_from_any_name(data);
1980 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1981 if (new_family != NULL)
1983 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1984 new_family->FamilyName = strdupW(value);
1985 new_family->EnglishName = NULL;
1986 list_init(&new_family->faces);
1987 new_family->replacement = &family->faces;
1988 list_add_tail(&font_list, &new_family->entry);
1993 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1998 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2000 /* reset dlen and vlen */
2004 HeapFree(GetProcessHeap(), 0, data);
2005 HeapFree(GetProcessHeap(), 0, value);
2010 static const WCHAR *font_links_list[] =
2012 Lucida_Sans_Unicode,
2013 Microsoft_Sans_Serif,
2017 static const struct font_links_defaults_list
2019 /* Keyed off substitution for "MS Shell Dlg" */
2020 const WCHAR *shelldlg;
2021 /* Maximum of four substitutes, plus terminating NULL pointer */
2022 const WCHAR *substitutes[5];
2023 } font_links_defaults_list[] =
2025 /* Non East-Asian */
2026 { Tahoma, /* FIXME unverified ordering */
2027 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2029 /* Below lists are courtesy of
2030 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2034 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2036 /* Chinese Simplified */
2038 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2042 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2044 /* Chinese Traditional */
2046 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2051 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2053 SYSTEM_LINKS *font_link;
2055 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2057 if(!strcmpiW(font_link->font_name, name))
2064 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2076 SYSTEM_LINKS *font_link;
2078 psub = get_font_subst(&font_subst_list, name, -1);
2079 /* Don't store fonts that are only substitutes for other fonts */
2082 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2086 font_link = find_font_link(name);
2087 if (font_link == NULL)
2089 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2090 font_link->font_name = strdupW(name);
2091 list_init(&font_link->links);
2092 list_add_tail(&system_links, &font_link->entry);
2095 memset(&font_link->fs, 0, sizeof font_link->fs);
2096 for (i = 0; values[i] != NULL; i++)
2098 const struct list *face_list;
2099 CHILD_FONT *child_font;
2102 if (!strcmpiW(name,value))
2104 psub = get_font_subst(&font_subst_list, value, -1);
2106 value = psub->to.name;
2107 family = find_family_from_name(value);
2111 /* Use first extant filename for this Family */
2112 face_list = get_face_list_from_family(family);
2113 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2117 file = strrchr(face->file, '/');
2126 fileW = towstr(CP_UNIXCP, file);
2128 face = find_face_from_filename(fileW, value);
2131 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2135 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2136 child_font->face = face;
2137 child_font->font = NULL;
2138 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2139 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2140 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2141 list_add_tail(&font_link->links, &child_font->entry);
2143 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2144 HeapFree(GetProcessHeap(), 0, fileW);
2150 /*************************************************************
2153 static BOOL init_system_links(void)
2157 DWORD type, max_val, max_data, val_len, data_len, index;
2158 WCHAR *value, *data;
2159 WCHAR *entry, *next;
2160 SYSTEM_LINKS *font_link, *system_font_link;
2161 CHILD_FONT *child_font;
2162 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2163 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2164 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2169 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2171 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2172 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2173 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2174 val_len = max_val + 1;
2175 data_len = max_data;
2177 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2179 psub = get_font_subst(&font_subst_list, value, -1);
2180 /* Don't store fonts that are only substitutes for other fonts */
2183 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2186 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2187 font_link->font_name = strdupW(value);
2188 memset(&font_link->fs, 0, sizeof font_link->fs);
2189 list_init(&font_link->links);
2190 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2193 CHILD_FONT *child_font;
2195 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2197 next = entry + strlenW(entry) + 1;
2199 face_name = strchrW(entry, ',');
2203 while(isspaceW(*face_name))
2206 psub = get_font_subst(&font_subst_list, face_name, -1);
2208 face_name = psub->to.name;
2210 face = find_face_from_filename(entry, face_name);
2213 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2217 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2218 child_font->face = face;
2219 child_font->font = NULL;
2220 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2221 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2222 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2223 list_add_tail(&font_link->links, &child_font->entry);
2225 list_add_tail(&system_links, &font_link->entry);
2227 val_len = max_val + 1;
2228 data_len = max_data;
2231 HeapFree(GetProcessHeap(), 0, value);
2232 HeapFree(GetProcessHeap(), 0, data);
2237 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2239 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2243 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2245 const FontSubst *psub2;
2246 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2248 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2250 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2251 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2253 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2254 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2256 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2258 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2264 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2267 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2268 system_font_link->font_name = strdupW(System);
2269 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2270 list_init(&system_font_link->links);
2272 face = find_face_from_filename(tahoma_ttf, Tahoma);
2275 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2276 child_font->face = face;
2277 child_font->font = NULL;
2278 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2279 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2280 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2281 list_add_tail(&system_font_link->links, &child_font->entry);
2283 font_link = find_font_link(Tahoma);
2284 if (font_link != NULL)
2286 CHILD_FONT *font_link_entry;
2287 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2289 CHILD_FONT *new_child;
2290 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2291 new_child->face = font_link_entry->face;
2292 new_child->font = NULL;
2293 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2294 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2295 list_add_tail(&system_font_link->links, &new_child->entry);
2298 list_add_tail(&system_links, &system_font_link->entry);
2302 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2305 struct dirent *dent;
2306 char path[MAX_PATH];
2308 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2310 dir = opendir(dirname);
2312 WARN("Can't open directory %s\n", debugstr_a(dirname));
2315 while((dent = readdir(dir)) != NULL) {
2316 struct stat statbuf;
2318 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2321 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2323 sprintf(path, "%s/%s", dirname, dent->d_name);
2325 if(stat(path, &statbuf) == -1)
2327 WARN("Can't stat %s\n", debugstr_a(path));
2330 if(S_ISDIR(statbuf.st_mode))
2331 ReadFontDir(path, external_fonts);
2334 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2335 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2336 AddFontToList(path, NULL, 0, addfont_flags);
2343 #ifdef SONAME_LIBFONTCONFIG
2344 static void load_fontconfig_fonts(void)
2346 void *fc_handle = NULL;
2355 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2357 TRACE("Wine cannot find the fontconfig library (%s).\n",
2358 SONAME_LIBFONTCONFIG);
2361 #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;}
2362 LOAD_FUNCPTR(FcConfigGetCurrent);
2363 LOAD_FUNCPTR(FcFontList);
2364 LOAD_FUNCPTR(FcFontSetDestroy);
2365 LOAD_FUNCPTR(FcInit);
2366 LOAD_FUNCPTR(FcObjectSetAdd);
2367 LOAD_FUNCPTR(FcObjectSetCreate);
2368 LOAD_FUNCPTR(FcObjectSetDestroy);
2369 LOAD_FUNCPTR(FcPatternCreate);
2370 LOAD_FUNCPTR(FcPatternDestroy);
2371 LOAD_FUNCPTR(FcPatternGetBool);
2372 LOAD_FUNCPTR(FcPatternGetString);
2375 if(!pFcInit()) return;
2377 config = pFcConfigGetCurrent();
2378 pat = pFcPatternCreate();
2379 os = pFcObjectSetCreate();
2380 pFcObjectSetAdd(os, FC_FILE);
2381 pFcObjectSetAdd(os, FC_SCALABLE);
2382 fontset = pFcFontList(config, pat, os);
2383 if(!fontset) return;
2384 for(i = 0; i < fontset->nfont; i++) {
2387 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2389 TRACE("fontconfig: %s\n", file);
2391 /* We're just interested in OT/TT fonts for now, so this hack just
2392 picks up the scalable fonts without extensions .pf[ab] to save time
2393 loading every other font */
2395 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2397 TRACE("not scalable\n");
2401 len = strlen( file );
2402 if(len < 4) continue;
2403 ext = &file[ len - 3 ];
2404 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2405 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2407 pFcFontSetDestroy(fontset);
2408 pFcObjectSetDestroy(os);
2409 pFcPatternDestroy(pat);
2414 #elif defined(HAVE_CARBON_CARBON_H)
2416 static void load_mac_font_callback(const void *value, void *context)
2418 CFStringRef pathStr = value;
2422 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2423 path = HeapAlloc(GetProcessHeap(), 0, len);
2424 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2426 TRACE("font file %s\n", path);
2427 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2429 HeapFree(GetProcessHeap(), 0, path);
2432 static void load_mac_fonts(void)
2434 CFStringRef removeDupesKey;
2435 CFBooleanRef removeDupesValue;
2436 CFDictionaryRef options;
2437 CTFontCollectionRef col;
2439 CFMutableSetRef paths;
2442 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2443 removeDupesValue = kCFBooleanTrue;
2444 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2445 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2446 col = CTFontCollectionCreateFromAvailableFonts(options);
2447 if (options) CFRelease(options);
2450 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2454 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2458 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2462 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2465 WARN("CFSetCreateMutable failed\n");
2470 for (i = 0; i < CFArrayGetCount(descs); i++)
2472 CTFontDescriptorRef desc;
2481 desc = CFArrayGetValueAtIndex(descs, i);
2483 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2484 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2485 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2486 if (!font) continue;
2488 atsFont = CTFontGetPlatformFont(font, NULL);
2495 status = ATSFontGetFileReference(atsFont, &fsref);
2497 if (status != noErr) continue;
2499 url = CFURLCreateFromFSRef(NULL, &fsref);
2502 ext = CFURLCopyPathExtension(url);
2505 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2506 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2515 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2517 if (!path) continue;
2519 CFSetAddValue(paths, path);
2525 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2531 static BOOL load_font_from_data_dir(LPCWSTR file)
2534 const char *data_dir = wine_get_data_dir();
2536 if (!data_dir) data_dir = wine_get_build_dir();
2543 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2545 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2547 strcpy(unix_name, data_dir);
2548 strcat(unix_name, "/fonts/");
2550 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2552 EnterCriticalSection( &freetype_cs );
2553 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2554 LeaveCriticalSection( &freetype_cs );
2555 HeapFree(GetProcessHeap(), 0, unix_name);
2560 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2562 static const WCHAR slashW[] = {'\\','\0'};
2564 WCHAR windowsdir[MAX_PATH];
2567 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2568 strcatW(windowsdir, fontsW);
2569 strcatW(windowsdir, slashW);
2570 strcatW(windowsdir, file);
2571 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2572 EnterCriticalSection( &freetype_cs );
2573 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2574 LeaveCriticalSection( &freetype_cs );
2575 HeapFree(GetProcessHeap(), 0, unixname);
2580 static void load_system_fonts(void)
2583 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2584 const WCHAR * const *value;
2586 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2589 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2590 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2591 strcatW(windowsdir, fontsW);
2592 for(value = SystemFontValues; *value; value++) {
2593 dlen = sizeof(data);
2594 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2598 sprintfW(pathW, fmtW, windowsdir, data);
2599 if((unixname = wine_get_unix_file_name(pathW))) {
2600 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2601 HeapFree(GetProcessHeap(), 0, unixname);
2604 load_font_from_data_dir(data);
2611 /*************************************************************
2613 * This adds registry entries for any externally loaded fonts
2614 * (fonts from fontconfig or FontDirs). It also deletes entries
2615 * of no longer existing fonts.
2618 static void update_reg_entries(void)
2620 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2625 struct list *family_elem_ptr, *face_elem_ptr;
2627 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2628 static const WCHAR spaceW[] = {' ', '\0'};
2631 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2632 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2633 ERR("Can't create Windows font reg key\n");
2637 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2638 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2639 ERR("Can't create Windows font reg key\n");
2643 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2644 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2645 ERR("Can't create external font reg key\n");
2649 /* enumerate the fonts and add external ones to the two keys */
2651 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2652 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2653 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2654 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2655 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2656 if(!face->external) continue;
2658 if (!(face->ntmFlags & NTM_REGULAR))
2659 len = len_fam + strlenW(face->StyleName) + 1;
2660 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2661 strcpyW(valueW, family->FamilyName);
2662 if(len != len_fam) {
2663 strcatW(valueW, spaceW);
2664 strcatW(valueW, face->StyleName);
2666 strcatW(valueW, TrueType);
2668 file = wine_get_dos_file_name(face->file);
2670 len = strlenW(file) + 1;
2673 if((path = strrchr(face->file, '/')) == NULL)
2677 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2679 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2680 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2682 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2683 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2684 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2686 HeapFree(GetProcessHeap(), 0, file);
2687 HeapFree(GetProcessHeap(), 0, valueW);
2691 if(external_key) RegCloseKey(external_key);
2692 if(win9x_key) RegCloseKey(win9x_key);
2693 if(winnt_key) RegCloseKey(winnt_key);
2697 static void delete_external_font_keys(void)
2699 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2700 DWORD dlen, vlen, datalen, valuelen, i, type;
2704 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2705 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2706 ERR("Can't create Windows font reg key\n");
2710 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2711 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2712 ERR("Can't create Windows font reg key\n");
2716 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2717 ERR("Can't create external font reg key\n");
2721 /* Delete all external fonts added last time */
2723 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2724 &valuelen, &datalen, NULL, NULL);
2725 valuelen++; /* returned value doesn't include room for '\0' */
2726 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2727 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2729 dlen = datalen * sizeof(WCHAR);
2732 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2733 &dlen) == ERROR_SUCCESS) {
2735 RegDeleteValueW(winnt_key, valueW);
2736 RegDeleteValueW(win9x_key, valueW);
2737 /* reset dlen and vlen */
2741 HeapFree(GetProcessHeap(), 0, data);
2742 HeapFree(GetProcessHeap(), 0, valueW);
2744 /* Delete the old external fonts key */
2745 RegCloseKey(external_key);
2746 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2749 if(win9x_key) RegCloseKey(win9x_key);
2750 if(winnt_key) RegCloseKey(winnt_key);
2753 /*************************************************************
2754 * WineEngAddFontResourceEx
2757 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2763 if (ft_handle) /* do it only if we have freetype up and running */
2768 FIXME("Ignoring flags %x\n", flags);
2770 if((unixname = wine_get_unix_file_name(file)))
2772 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2774 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2775 EnterCriticalSection( &freetype_cs );
2776 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2777 LeaveCriticalSection( &freetype_cs );
2778 HeapFree(GetProcessHeap(), 0, unixname);
2780 if (!ret && !strchrW(file, '\\')) {
2781 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2782 ret = load_font_from_winfonts_dir(file);
2784 /* Try in datadir/fonts (or builddir/fonts),
2785 * needed for Magic the Gathering Online
2787 ret = load_font_from_data_dir(file);
2794 /*************************************************************
2795 * WineEngAddFontMemResourceEx
2798 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2802 if (ft_handle) /* do it only if we have freetype up and running */
2804 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2806 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2807 memcpy(pFontCopy, pbFont, cbFont);
2809 EnterCriticalSection( &freetype_cs );
2810 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2811 LeaveCriticalSection( &freetype_cs );
2815 TRACE("AddFontToList failed\n");
2816 HeapFree(GetProcessHeap(), 0, pFontCopy);
2819 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2820 * For now return something unique but quite random
2822 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2823 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2830 /*************************************************************
2831 * WineEngRemoveFontResourceEx
2834 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2837 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2841 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2847 if (!font_file) return NULL;
2849 file_len = strlenW( font_file );
2851 if (font_path && font_path[0])
2853 int path_len = strlenW( font_path );
2854 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2855 if (!fullname) return NULL;
2856 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2857 fullname[path_len] = '\\';
2858 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2862 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2863 if (!len) return NULL;
2864 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2865 if (!fullname) return NULL;
2866 GetFullPathNameW( font_file, len, fullname, NULL );
2869 unix_name = wine_get_unix_file_name( fullname );
2870 HeapFree( GetProcessHeap(), 0, fullname );
2874 #include <pshpack1.h>
2877 WORD num_of_resources;
2881 CHAR dfCopyright[60];
2887 WORD dfInternalLeading;
2888 WORD dfExternalLeading;
2896 BYTE dfPitchAndFamily;
2907 CHAR szFaceName[LF_FACESIZE];
2910 #include <poppack.h>
2912 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2913 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2915 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2917 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2920 WCHAR *name, *english_name;
2922 NEWTEXTMETRICEXW ntm;
2925 if (!ft_face) return FALSE;
2926 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE );
2927 get_family_names( ft_face, &name, &english_name, FALSE );
2928 family = create_family( name, english_name );
2929 insert_face_in_family_list( face, family );
2930 pFT_Done_Face( ft_face );
2932 GetEnumStructs( face, &elf, &ntm, &type );
2933 free_family( family );
2935 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
2937 memset( fd, 0, sizeof(*fd) );
2939 fd->num_of_resources = 1;
2941 fd->dfVersion = 0x200;
2942 fd->dfSize = sizeof(*fd);
2943 strcpy( fd->dfCopyright, "Wine fontdir" );
2944 fd->dfType = 0x4003; /* 0x0080 set if private */
2945 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
2947 fd->dfHorizRes = 72;
2948 fd->dfAscent = ntm.ntmTm.tmAscent;
2949 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
2950 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
2951 fd->dfItalic = ntm.ntmTm.tmItalic;
2952 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
2953 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
2954 fd->dfWeight = ntm.ntmTm.tmWeight;
2955 fd->dfCharSet = ntm.ntmTm.tmCharSet;
2957 fd->dfPixHeight = ntm.ntmTm.tmHeight;
2958 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
2959 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
2960 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
2961 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
2962 fd->dfLastChar = ntm.ntmTm.tmLastChar;
2963 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
2964 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
2965 fd->dfWidthBytes = 0;
2967 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
2969 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
2974 #define NE_FFLAGS_LIBMODULE 0x8000
2975 #define NE_OSFLAGS_WINDOWS 0x02
2977 static const char dos_string[0x40] = "This is a TrueType resource file";
2978 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
2980 #include <pshpack2.h>
3001 struct ne_typeinfo fontdir_type;
3002 struct ne_nameinfo fontdir_name;
3003 struct ne_typeinfo scalable_type;
3004 struct ne_nameinfo scalable_name;
3006 BYTE fontdir_res_name[8];
3009 #include <poppack.h>
3011 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3015 DWORD size, written;
3017 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3018 char *font_fileA, *last_part, *ext;
3019 IMAGE_DOS_HEADER dos;
3020 IMAGE_OS2_HEADER ne =
3022 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3024 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3025 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3027 struct rsrc_tab rsrc_tab =
3031 { 0, 0, 0x0c50, 0x2c, 0 },
3033 { 0, 0, 0x0c50, 0x8001, 0 },
3035 { 7,'F','O','N','T','D','I','R'}
3038 memset( &dos, 0, sizeof(dos) );
3039 dos.e_magic = IMAGE_DOS_SIGNATURE;
3040 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3042 /* import name is last part\0, resident name is last part without extension
3043 non-resident name is "FONTRES:" + lfFaceName */
3045 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3046 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3047 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3049 last_part = strrchr( font_fileA, '\\' );
3050 if (last_part) last_part++;
3051 else last_part = font_fileA;
3052 import_name_len = strlen( last_part ) + 1;
3054 ext = strchr( last_part, '.' );
3055 if (ext) res_name_len = ext - last_part;
3056 else res_name_len = import_name_len - 1;
3058 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3060 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3061 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3062 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3063 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3065 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3067 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3068 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3069 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3070 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3072 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3073 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3077 HeapFree( GetProcessHeap(), 0, font_fileA );
3081 memcpy( ptr, &dos, sizeof(dos) );
3082 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3083 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3085 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3086 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3088 ptr = start + dos.e_lfanew + ne.ne_restab;
3089 *ptr++ = res_name_len;
3090 memcpy( ptr, last_part, res_name_len );
3092 ptr = start + dos.e_lfanew + ne.ne_imptab;
3093 *ptr++ = import_name_len;
3094 memcpy( ptr, last_part, import_name_len );
3096 ptr = start + ne.ne_nrestab;
3097 *ptr++ = non_res_name_len;
3098 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3099 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3101 ptr = start + (rsrc_tab.scalable_name.off << 4);
3102 memcpy( ptr, font_fileA, font_file_len );
3104 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3105 memcpy( ptr, fontdir, fontdir->dfSize );
3107 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3108 if (file != INVALID_HANDLE_VALUE)
3110 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3112 CloseHandle( file );
3115 HeapFree( GetProcessHeap(), 0, start );
3116 HeapFree( GetProcessHeap(), 0, font_fileA );
3121 /*************************************************************
3122 * WineEngCreateScalableFontResource
3125 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3126 LPCWSTR font_file, LPCWSTR font_path )
3128 char *unix_name = get_ttf_file_name( font_file, font_path );
3129 struct fontdir fontdir;
3132 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3133 SetLastError( ERROR_INVALID_PARAMETER );
3136 if (hidden) fontdir.dfType |= 0x80;
3137 ret = create_fot( resource, font_file, &fontdir );
3140 HeapFree( GetProcessHeap(), 0, unix_name );
3144 static const struct nls_update_font_list
3146 UINT ansi_cp, oem_cp;
3147 const char *oem, *fixed, *system;
3148 const char *courier, *serif, *small, *sserif;
3149 /* these are for font substitutes */
3150 const char *shelldlg, *tmsrmn;
3151 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3155 const char *from, *to;
3156 } arial_0, courier_new_0, times_new_roman_0;
3157 } nls_update_font_list[] =
3159 /* Latin 1 (United States) */
3160 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3161 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3162 "Tahoma","Times New Roman",
3163 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3166 /* Latin 1 (Multilingual) */
3167 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3168 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3169 "Tahoma","Times New Roman", /* FIXME unverified */
3170 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3173 /* Eastern Europe */
3174 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3175 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
3176 "Tahoma","Times New Roman", /* FIXME unverified */
3177 "Fixedsys,238", "System,238",
3178 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3179 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3180 { "Arial CE,0", "Arial,238" },
3181 { "Courier New CE,0", "Courier New,238" },
3182 { "Times New Roman CE,0", "Times New Roman,238" }
3185 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3186 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
3187 "Tahoma","Times New Roman", /* FIXME unverified */
3188 "Fixedsys,204", "System,204",
3189 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3190 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3191 { "Arial Cyr,0", "Arial,204" },
3192 { "Courier New Cyr,0", "Courier New,204" },
3193 { "Times New Roman Cyr,0", "Times New Roman,204" }
3196 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3197 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
3198 "Tahoma","Times New Roman", /* FIXME unverified */
3199 "Fixedsys,161", "System,161",
3200 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3201 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3202 { "Arial Greek,0", "Arial,161" },
3203 { "Courier New Greek,0", "Courier New,161" },
3204 { "Times New Roman Greek,0", "Times New Roman,161" }
3207 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3208 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
3209 "Tahoma","Times New Roman", /* FIXME unverified */
3210 "Fixedsys,162", "System,162",
3211 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3212 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3213 { "Arial Tur,0", "Arial,162" },
3214 { "Courier New Tur,0", "Courier New,162" },
3215 { "Times New Roman Tur,0", "Times New Roman,162" }
3218 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3219 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
3220 "Tahoma","Times New Roman", /* FIXME unverified */
3221 "Fixedsys,177", "System,177",
3222 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3223 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3227 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3228 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
3229 "Tahoma","Times New Roman", /* FIXME unverified */
3230 "Fixedsys,178", "System,178",
3231 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3232 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3236 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3237 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
3238 "Tahoma","Times New Roman", /* FIXME unverified */
3239 "Fixedsys,186", "System,186",
3240 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3241 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3242 { "Arial Baltic,0", "Arial,186" },
3243 { "Courier New Baltic,0", "Courier New,186" },
3244 { "Times New Roman Baltic,0", "Times New Roman,186" }
3247 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3248 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3249 "Tahoma","Times New Roman", /* FIXME unverified */
3250 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3254 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3255 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
3256 "Tahoma","Times New Roman", /* FIXME unverified */
3257 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3261 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3262 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
3263 "MS UI Gothic","MS Serif",
3264 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3267 /* Chinese Simplified */
3268 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3269 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3270 "SimSun", "NSimSun",
3271 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3275 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3276 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3278 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3281 /* Chinese Traditional */
3282 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3283 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3284 "PMingLiU", "MingLiU",
3285 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3290 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3292 return ( ansi_cp == 932 /* CP932 for Japanese */
3293 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3294 || ansi_cp == 949 /* CP949 for Korean */
3295 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3298 static inline HKEY create_fonts_NT_registry_key(void)
3302 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3303 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3307 static inline HKEY create_fonts_9x_registry_key(void)
3311 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3312 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3316 static inline HKEY create_config_fonts_registry_key(void)
3320 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3321 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3325 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
3327 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3328 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3329 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
3330 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3333 static void set_value_key(HKEY hkey, const char *name, const char *value)
3336 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3338 RegDeleteValueA(hkey, name);
3341 static void update_font_info(void)
3343 char buf[40], cpbuf[40];
3346 UINT i, ansi_cp = 0, oem_cp = 0;
3349 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3352 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3353 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3354 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3355 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3356 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3358 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3359 if (is_dbcs_ansi_cp(ansi_cp))
3360 use_default_fallback = TRUE;
3363 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3365 if (!strcmp( buf, cpbuf )) /* already set correctly */
3370 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
3372 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
3374 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3377 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3381 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3382 nls_update_font_list[i].oem_cp == oem_cp)
3384 hkey = create_config_fonts_registry_key();
3385 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3386 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3387 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3390 hkey = create_fonts_NT_registry_key();
3391 add_font_list(hkey, &nls_update_font_list[i]);
3394 hkey = create_fonts_9x_registry_key();
3395 add_font_list(hkey, &nls_update_font_list[i]);
3398 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3400 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3401 strlen(nls_update_font_list[i].shelldlg)+1);
3402 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3403 strlen(nls_update_font_list[i].tmsrmn)+1);
3405 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3406 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3407 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3408 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3409 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3410 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3411 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3412 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3414 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3415 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3416 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3424 /* Delete the FontSubstitutes from other locales */
3425 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3427 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3428 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3429 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3435 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3438 static BOOL init_freetype(void)
3440 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3443 "Wine cannot find the FreeType font library. To enable Wine to\n"
3444 "use TrueType fonts please install a version of FreeType greater than\n"
3445 "or equal to 2.0.5.\n"
3446 "http://www.freetype.org\n");
3450 #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;}
3452 LOAD_FUNCPTR(FT_Done_Face)
3453 LOAD_FUNCPTR(FT_Get_Char_Index)
3454 LOAD_FUNCPTR(FT_Get_First_Char)
3455 LOAD_FUNCPTR(FT_Get_Module)
3456 LOAD_FUNCPTR(FT_Get_Next_Char)
3457 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3458 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3459 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3460 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3461 LOAD_FUNCPTR(FT_Init_FreeType)
3462 LOAD_FUNCPTR(FT_Library_Version)
3463 LOAD_FUNCPTR(FT_Load_Glyph)
3464 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3465 LOAD_FUNCPTR(FT_Matrix_Multiply)
3466 #ifndef FT_MULFIX_INLINED
3467 LOAD_FUNCPTR(FT_MulFix)
3469 LOAD_FUNCPTR(FT_New_Face)
3470 LOAD_FUNCPTR(FT_New_Memory_Face)
3471 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3472 LOAD_FUNCPTR(FT_Outline_Transform)
3473 LOAD_FUNCPTR(FT_Outline_Translate)
3474 LOAD_FUNCPTR(FT_Render_Glyph)
3475 LOAD_FUNCPTR(FT_Select_Charmap)
3476 LOAD_FUNCPTR(FT_Set_Charmap)
3477 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3478 LOAD_FUNCPTR(FT_Vector_Transform)
3479 LOAD_FUNCPTR(FT_Vector_Unit)
3481 /* Don't warn if these ones are missing */
3482 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3483 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3484 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3487 if(pFT_Init_FreeType(&library) != 0) {
3488 ERR("Can't init FreeType library\n");
3489 wine_dlclose(ft_handle, NULL, 0);
3493 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3495 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3496 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3497 ((FT_Version.minor << 8) & 0x00ff00) |
3498 ((FT_Version.patch ) & 0x0000ff);
3500 font_driver = &freetype_funcs;
3505 "Wine cannot find certain functions that it needs inside the FreeType\n"
3506 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3507 "FreeType to at least version 2.1.4.\n"
3508 "http://www.freetype.org\n");
3509 wine_dlclose(ft_handle, NULL, 0);
3514 static void init_font_list(void)
3516 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3517 static const WCHAR pathW[] = {'P','a','t','h',0};
3519 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3520 WCHAR windowsdir[MAX_PATH];
3522 const char *data_dir;
3524 delete_external_font_keys();
3526 /* load the system bitmap fonts */
3527 load_system_fonts();
3529 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3530 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3531 strcatW(windowsdir, fontsW);
3532 if((unixname = wine_get_unix_file_name(windowsdir)))
3534 ReadFontDir(unixname, FALSE);
3535 HeapFree(GetProcessHeap(), 0, unixname);
3538 /* load the system truetype fonts */
3539 data_dir = wine_get_data_dir();
3540 if (!data_dir) data_dir = wine_get_build_dir();
3541 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3543 strcpy(unixname, data_dir);
3544 strcat(unixname, "/fonts/");
3545 ReadFontDir(unixname, TRUE);
3546 HeapFree(GetProcessHeap(), 0, unixname);
3549 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3550 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3551 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3553 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3554 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3555 &hkey) == ERROR_SUCCESS)
3557 LPWSTR data, valueW;
3558 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3559 &valuelen, &datalen, NULL, NULL);
3561 valuelen++; /* returned value doesn't include room for '\0' */
3562 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3563 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3566 dlen = datalen * sizeof(WCHAR);
3568 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3569 &dlen) == ERROR_SUCCESS)
3571 if(data[0] && (data[1] == ':'))
3573 if((unixname = wine_get_unix_file_name(data)))
3575 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3576 HeapFree(GetProcessHeap(), 0, unixname);
3579 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3581 WCHAR pathW[MAX_PATH];
3582 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3585 sprintfW(pathW, fmtW, windowsdir, data);
3586 if((unixname = wine_get_unix_file_name(pathW)))
3588 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3589 HeapFree(GetProcessHeap(), 0, unixname);
3592 load_font_from_data_dir(data);
3594 /* reset dlen and vlen */
3599 HeapFree(GetProcessHeap(), 0, data);
3600 HeapFree(GetProcessHeap(), 0, valueW);
3604 #ifdef SONAME_LIBFONTCONFIG
3605 load_fontconfig_fonts();
3606 #elif defined(HAVE_CARBON_CARBON_H)
3610 /* then look in any directories that we've specified in the config file */
3611 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3612 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3618 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3620 len += sizeof(WCHAR);
3621 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3622 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3624 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3625 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3626 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3627 TRACE( "got font path %s\n", debugstr_a(valueA) );
3632 LPSTR next = strchr( ptr, ':' );
3633 if (next) *next++ = 0;
3634 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3635 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3637 strcpy( unixname, home );
3638 strcat( unixname, ptr + 1 );
3639 ReadFontDir( unixname, TRUE );
3640 HeapFree( GetProcessHeap(), 0, unixname );
3643 ReadFontDir( ptr, TRUE );
3646 HeapFree( GetProcessHeap(), 0, valueA );
3648 HeapFree( GetProcessHeap(), 0, valueW );
3654 static BOOL move_to_front(const WCHAR *name)
3656 Family *family, *cursor2;
3657 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3659 if(!strcmpiW(family->FamilyName, name))
3661 list_remove(&family->entry);
3662 list_add_head(&font_list, &family->entry);
3669 static BOOL set_default(const WCHAR **name_list)
3673 if (move_to_front(*name_list)) return TRUE;
3680 static void reorder_font_list(void)
3682 set_default( default_serif_list );
3683 set_default( default_fixed_list );
3684 set_default( default_sans_list );
3687 /*************************************************************
3690 * Initialize FreeType library and create a list of available faces
3692 BOOL WineEngInit(void)
3694 HKEY hkey_font_cache;
3698 /* update locale dependent font info in registry */
3701 if(!init_freetype()) return FALSE;
3703 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3705 ERR("Failed to create font mutex\n");
3708 WaitForSingleObject(font_mutex, INFINITE);
3710 create_font_cache_key(&hkey_font_cache, &disposition);
3712 if(disposition == REG_CREATED_NEW_KEY)
3715 load_font_list_from_cache(hkey_font_cache);
3717 RegCloseKey(hkey_font_cache);
3719 reorder_font_list();
3726 if(disposition == REG_CREATED_NEW_KEY)
3727 update_reg_entries();
3729 init_system_links();
3731 ReleaseMutex(font_mutex);
3736 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3739 TT_HoriHeader *pHori;
3743 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3744 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3746 if(height == 0) height = 16;
3748 /* Calc. height of EM square:
3750 * For +ve lfHeight we have
3751 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3752 * Re-arranging gives:
3753 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3755 * For -ve lfHeight we have
3757 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3758 * with il = winAscent + winDescent - units_per_em]
3763 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3764 ppem = MulDiv(ft_face->units_per_EM, height,
3765 pHori->Ascender - pHori->Descender);
3767 ppem = MulDiv(ft_face->units_per_EM, height,
3768 pOS2->usWinAscent + pOS2->usWinDescent);
3776 static struct font_mapping *map_font_file( const char *name )
3778 struct font_mapping *mapping;
3782 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3783 if (fstat( fd, &st ) == -1) goto error;
3785 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3787 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3789 mapping->refcount++;
3794 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3797 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3800 if (mapping->data == MAP_FAILED)
3802 HeapFree( GetProcessHeap(), 0, mapping );
3805 mapping->refcount = 1;
3806 mapping->dev = st.st_dev;
3807 mapping->ino = st.st_ino;
3808 mapping->size = st.st_size;
3809 list_add_tail( &mappings_list, &mapping->entry );
3817 static void unmap_font_file( struct font_mapping *mapping )
3819 if (!--mapping->refcount)
3821 list_remove( &mapping->entry );
3822 munmap( mapping->data, mapping->size );
3823 HeapFree( GetProcessHeap(), 0, mapping );
3827 static LONG load_VDMX(GdiFont*, LONG);
3829 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3836 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3840 if (!(font->mapping = map_font_file( face->file )))
3842 WARN("failed to map %s\n", debugstr_a(face->file));
3845 data_ptr = font->mapping->data;
3846 data_size = font->mapping->size;
3850 data_ptr = face->font_data_ptr;
3851 data_size = face->font_data_size;
3854 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3856 ERR("FT_New_Face rets %d\n", err);
3860 /* set it here, as load_VDMX needs it */
3861 font->ft_face = ft_face;
3863 if(FT_IS_SCALABLE(ft_face)) {
3864 /* load the VDMX table if we have one */
3865 font->ppem = load_VDMX(font, height);
3867 font->ppem = calc_ppem_for_height(ft_face, height);
3868 TRACE("height %d => ppem %d\n", height, font->ppem);
3870 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3871 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3873 font->ppem = height;
3874 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3875 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3881 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3883 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3884 a single face with the requested charset. The idea is to check if
3885 the selected font supports the current ANSI codepage, if it does
3886 return the corresponding charset, else return the first charset */
3889 int acp = GetACP(), i;
3893 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3895 const SYSTEM_LINKS *font_link;
3897 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3898 return csi.ciCharset;
3900 font_link = find_font_link(family_name);
3901 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3902 return csi.ciCharset;
3905 for(i = 0; i < 32; i++) {
3907 if(face->fs.fsCsb[0] & fs0) {
3908 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3910 return csi.ciCharset;
3913 FIXME("TCI failing on %x\n", fs0);
3917 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3918 face->fs.fsCsb[0], face->file);
3920 return DEFAULT_CHARSET;
3923 static GdiFont *alloc_font(void)
3925 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3927 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3928 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3930 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3931 ret->total_kern_pairs = (DWORD)-1;
3932 ret->kern_pairs = NULL;
3933 list_init(&ret->hfontlist);
3934 list_init(&ret->child_fonts);
3938 static void free_font(GdiFont *font)
3940 struct list *cursor, *cursor2;
3943 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3945 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3946 list_remove(cursor);
3948 free_font(child->font);
3949 HeapFree(GetProcessHeap(), 0, child);
3952 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3954 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3955 DeleteObject(hfontlist->hfont);
3956 list_remove(&hfontlist->entry);
3957 HeapFree(GetProcessHeap(), 0, hfontlist);
3960 if (font->ft_face) pFT_Done_Face(font->ft_face);
3961 if (font->mapping) unmap_font_file( font->mapping );
3962 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3963 HeapFree(GetProcessHeap(), 0, font->potm);
3964 HeapFree(GetProcessHeap(), 0, font->name);
3965 for (i = 0; i < font->gmsize; i++)
3966 HeapFree(GetProcessHeap(),0,font->gm[i]);
3967 HeapFree(GetProcessHeap(), 0, font->gm);
3968 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3969 HeapFree(GetProcessHeap(), 0, font);
3973 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3975 FT_Face ft_face = font->ft_face;
3979 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3986 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3988 /* make sure value of len is the value freetype says it needs */
3991 FT_ULong needed = 0;
3992 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3993 if( !err && needed < len) len = needed;
3995 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3998 TRACE("Can't find table %c%c%c%c\n",
3999 /* bytes were reversed */
4000 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4001 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4007 /*************************************************************
4010 * load the vdmx entry for the specified height
4013 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4014 ( ( (FT_ULong)_x4 << 24 ) | \
4015 ( (FT_ULong)_x3 << 16 ) | \
4016 ( (FT_ULong)_x2 << 8 ) | \
4019 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4034 static LONG load_VDMX(GdiFont *font, LONG height)
4038 BYTE devXRatio, devYRatio;
4039 USHORT numRecs, numRatios;
4040 DWORD result, offset = -1;
4044 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4046 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4049 /* FIXME: need the real device aspect ratio */
4053 numRecs = GET_BE_WORD(hdr[1]);
4054 numRatios = GET_BE_WORD(hdr[2]);
4056 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4057 for(i = 0; i < numRatios; i++) {
4060 offset = (3 * 2) + (i * sizeof(Ratios));
4061 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4064 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4066 if((ratio.xRatio == 0 &&
4067 ratio.yStartRatio == 0 &&
4068 ratio.yEndRatio == 0) ||
4069 (devXRatio == ratio.xRatio &&
4070 devYRatio >= ratio.yStartRatio &&
4071 devYRatio <= ratio.yEndRatio))
4073 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4074 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4075 offset = GET_BE_WORD(tmp);
4081 FIXME("No suitable ratio found\n");
4085 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4087 BYTE startsz, endsz;
4090 recs = GET_BE_WORD(group.recs);
4091 startsz = group.startsz;
4092 endsz = group.endsz;
4094 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4096 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4097 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4098 if(result == GDI_ERROR) {
4099 FIXME("Failed to retrieve vTable\n");
4104 for(i = 0; i < recs; i++) {
4105 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4106 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4107 ppem = GET_BE_WORD(vTable[i * 3]);
4109 if(yMax + -yMin == height) {
4112 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4115 if(yMax + -yMin > height) {
4118 goto end; /* failed */
4120 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4121 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4122 ppem = GET_BE_WORD(vTable[i * 3]);
4123 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4129 TRACE("ppem not found for height %d\n", height);
4133 HeapFree(GetProcessHeap(), 0, vTable);
4139 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4141 if(font->font_desc.hash != fd->hash) return TRUE;
4142 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4143 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4144 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4145 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4148 static void calc_hash(FONT_DESC *pfd)
4150 DWORD hash = 0, *ptr, two_chars;
4154 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4156 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4158 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4160 pwc = (WCHAR *)&two_chars;
4162 *pwc = toupperW(*pwc);
4164 *pwc = toupperW(*pwc);
4168 hash ^= !pfd->can_use_bitmap;
4173 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4178 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4182 fd.can_use_bitmap = can_use_bitmap;
4185 /* try the child list */
4186 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4187 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4188 if(!fontcmp(ret, &fd)) {
4189 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4190 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4191 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4192 if(hflist->hfont == hfont)
4198 /* try the in-use list */
4199 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4200 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4201 if(!fontcmp(ret, &fd)) {
4202 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4203 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4204 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4205 if(hflist->hfont == hfont)
4208 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4209 hflist->hfont = hfont;
4210 list_add_head(&ret->hfontlist, &hflist->entry);
4215 /* then the unused list */
4216 font_elem_ptr = list_head(&unused_gdi_font_list);
4217 while(font_elem_ptr) {
4218 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4219 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4220 if(!fontcmp(ret, &fd)) {
4221 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4222 assert(list_empty(&ret->hfontlist));
4223 TRACE("Found %p in unused list\n", ret);
4224 list_remove(&ret->entry);
4225 list_add_head(&gdi_font_list, &ret->entry);
4226 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4227 hflist->hfont = hfont;
4228 list_add_head(&ret->hfontlist, &hflist->entry);
4235 static void add_to_cache(GdiFont *font)
4237 static DWORD cache_num = 1;
4239 font->cache_num = cache_num++;
4240 list_add_head(&gdi_font_list, &font->entry);
4243 /*************************************************************
4244 * create_child_font_list
4246 static BOOL create_child_font_list(GdiFont *font)
4249 SYSTEM_LINKS *font_link;
4250 CHILD_FONT *font_link_entry, *new_child;
4254 psub = get_font_subst(&font_subst_list, font->name, -1);
4255 font_name = psub ? psub->to.name : font->name;
4256 font_link = find_font_link(font_name);
4257 if (font_link != NULL)
4259 TRACE("found entry in system list\n");
4260 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4262 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4263 new_child->face = font_link_entry->face;
4264 new_child->font = NULL;
4265 list_add_tail(&font->child_fonts, &new_child->entry);
4266 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4271 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4272 * Sans Serif. This is how asian windows get default fallbacks for fonts
4274 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4275 font->charset != OEM_CHARSET &&
4276 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4278 font_link = find_font_link(szDefaultFallbackLink);
4279 if (font_link != NULL)
4281 TRACE("found entry in default fallback list\n");
4282 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4284 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4285 new_child->face = font_link_entry->face;
4286 new_child->font = NULL;
4287 list_add_tail(&font->child_fonts, &new_child->entry);
4288 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4297 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4299 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4301 if (pFT_Set_Charmap)
4304 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4306 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4308 for (i = 0; i < ft_face->num_charmaps; i++)
4310 if (ft_face->charmaps[i]->encoding == encoding)
4312 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4313 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4315 switch (ft_face->charmaps[i]->platform_id)
4318 cmap_def = ft_face->charmaps[i];
4320 case 0: /* Apple Unicode */
4321 cmap0 = ft_face->charmaps[i];
4323 case 1: /* Macintosh */
4324 cmap1 = ft_face->charmaps[i];
4327 cmap2 = ft_face->charmaps[i];
4329 case 3: /* Microsoft */
4330 cmap3 = ft_face->charmaps[i];
4335 if (cmap3) /* prefer Microsoft cmap table */
4336 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4338 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4340 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4342 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4344 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4346 return ft_err == FT_Err_Ok;
4349 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4353 /*************************************************************
4356 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4357 LPCWSTR output, const DEVMODEW *devmode )
4359 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4361 if (!physdev) return FALSE;
4362 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4367 /*************************************************************
4370 static BOOL freetype_DeleteDC( PHYSDEV dev )
4372 struct freetype_physdev *physdev = get_freetype_dev( dev );
4373 HeapFree( GetProcessHeap(), 0, physdev );
4378 /*************************************************************
4379 * freetype_SelectFont
4381 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4383 struct freetype_physdev *physdev = get_freetype_dev( dev );
4385 Face *face, *best, *best_bitmap;
4386 Family *family, *last_resort_family;
4387 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4388 INT height, width = 0;
4389 unsigned int score = 0, new_score;
4390 signed int diff = 0, newdiff;
4391 BOOL bd, it, can_use_bitmap, want_vertical;
4396 FontSubst *psub = NULL;
4397 DC *dc = get_dc_ptr( dev->hdc );
4398 const SYSTEM_LINKS *font_link;
4400 if (!hfont) /* notification that the font has been changed by another driver */
4403 physdev->font = NULL;
4404 release_dc_ptr( dc );
4408 GetObjectW( hfont, sizeof(lf), &lf );
4409 lf.lfWidth = abs(lf.lfWidth);
4411 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4413 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4414 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4415 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4418 if(dc->GraphicsMode == GM_ADVANCED)
4420 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4421 /* Try to avoid not necessary glyph transformations */
4422 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4424 lf.lfHeight *= fabs(dcmat.eM11);
4425 lf.lfWidth *= fabs(dcmat.eM11);
4426 dcmat.eM11 = dcmat.eM22 = 1.0;
4431 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4432 font scaling abilities. */
4433 dcmat.eM11 = dcmat.eM22 = 1.0;
4434 dcmat.eM21 = dcmat.eM12 = 0;
4435 if (dc->vport2WorldValid)
4437 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4438 lf.lfOrientation = -lf.lfOrientation;
4439 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4440 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4444 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4445 dcmat.eM21, dcmat.eM22);
4448 EnterCriticalSection( &freetype_cs );
4450 /* check the cache first */
4451 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4452 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4456 if(list_empty(&font_list)) /* No fonts installed */
4458 TRACE("No fonts installed\n");
4462 TRACE("not in cache\n");
4465 ret->font_desc.matrix = dcmat;
4466 ret->font_desc.lf = lf;
4467 ret->font_desc.can_use_bitmap = can_use_bitmap;
4468 calc_hash(&ret->font_desc);
4469 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4470 hflist->hfont = hfont;
4471 list_add_head(&ret->hfontlist, &hflist->entry);
4473 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4474 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4475 original value lfCharSet. Note this is a special case for
4476 Symbol and doesn't happen at least for "Wingdings*" */
4478 if(!strcmpiW(lf.lfFaceName, SymbolW))
4479 lf.lfCharSet = SYMBOL_CHARSET;
4481 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4482 switch(lf.lfCharSet) {
4483 case DEFAULT_CHARSET:
4484 csi.fs.fsCsb[0] = 0;
4487 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4488 csi.fs.fsCsb[0] = 0;
4494 if(lf.lfFaceName[0] != '\0') {
4495 CHILD_FONT *font_link_entry;
4496 LPWSTR FaceName = lf.lfFaceName;
4498 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4501 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4502 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4503 if (psub->to.charset != -1)
4504 lf.lfCharSet = psub->to.charset;
4507 /* We want a match on name and charset or just name if
4508 charset was DEFAULT_CHARSET. If the latter then
4509 we fixup the returned charset later in get_nearest_charset
4510 where we'll either use the charset of the current ansi codepage
4511 or if that's unavailable the first charset that the font supports.
4513 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4514 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4515 if (!strcmpiW(family->FamilyName, FaceName) ||
4516 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4518 font_link = find_font_link(family->FamilyName);
4519 face_list = get_face_list_from_family(family);
4520 LIST_FOR_EACH(face_elem_ptr, face_list) {
4521 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4522 if (!(face->scalable || can_use_bitmap))
4524 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4526 if (font_link != NULL &&
4527 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4529 if (!csi.fs.fsCsb[0])
4535 /* Search by full face name. */
4536 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4537 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4538 face_list = get_face_list_from_family(family);
4539 LIST_FOR_EACH(face_elem_ptr, face_list) {
4540 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4541 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4542 (face->scalable || can_use_bitmap))
4544 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4546 font_link = find_font_link(family->FamilyName);
4547 if (font_link != NULL &&
4548 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4555 * Try check the SystemLink list first for a replacement font.
4556 * We may find good replacements there.
4558 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4560 if(!strcmpiW(font_link->font_name, FaceName) ||
4561 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4563 TRACE("found entry in system list\n");
4564 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4566 const SYSTEM_LINKS *links;
4568 face = font_link_entry->face;
4569 if (!(face->scalable || can_use_bitmap))
4571 family = face->family;
4572 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4574 links = find_font_link(family->FamilyName);
4575 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4582 psub = NULL; /* substitution is no more relevant */
4584 /* If requested charset was DEFAULT_CHARSET then try using charset
4585 corresponding to the current ansi codepage */
4586 if (!csi.fs.fsCsb[0])
4589 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4590 FIXME("TCI failed on codepage %d\n", acp);
4591 csi.fs.fsCsb[0] = 0;
4593 lf.lfCharSet = csi.ciCharset;
4596 want_vertical = (lf.lfFaceName[0] == '@');
4598 /* Face families are in the top 4 bits of lfPitchAndFamily,
4599 so mask with 0xF0 before testing */
4601 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4602 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4603 strcpyW(lf.lfFaceName, defFixed);
4604 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4605 strcpyW(lf.lfFaceName, defSerif);
4606 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4607 strcpyW(lf.lfFaceName, defSans);
4609 strcpyW(lf.lfFaceName, defSans);
4610 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4611 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4612 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4613 font_link = find_font_link(family->FamilyName);
4614 face_list = get_face_list_from_family(family);
4615 LIST_FOR_EACH(face_elem_ptr, face_list) {
4616 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4617 if (!(face->scalable || can_use_bitmap))
4619 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4621 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4627 last_resort_family = NULL;
4628 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4629 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4630 font_link = find_font_link(family->FamilyName);
4631 face_list = get_face_list_from_family(family);
4632 LIST_FOR_EACH(face_elem_ptr, face_list) {
4633 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4634 if(face->vertical == want_vertical &&
4635 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4636 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4639 if(can_use_bitmap && !last_resort_family)
4640 last_resort_family = family;
4645 if(last_resort_family) {
4646 family = last_resort_family;
4647 csi.fs.fsCsb[0] = 0;
4651 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4652 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4653 face_list = get_face_list_from_family(family);
4654 LIST_FOR_EACH(face_elem_ptr, face_list) {
4655 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4656 if(face->scalable && face->vertical == want_vertical) {
4657 csi.fs.fsCsb[0] = 0;
4658 WARN("just using first face for now\n");
4661 if(can_use_bitmap && !last_resort_family)
4662 last_resort_family = family;
4665 if(!last_resort_family) {
4666 FIXME("can't find a single appropriate font - bailing\n");
4672 WARN("could only find a bitmap font - this will probably look awful!\n");
4673 family = last_resort_family;
4674 csi.fs.fsCsb[0] = 0;
4677 it = lf.lfItalic ? 1 : 0;
4678 bd = lf.lfWeight > 550 ? 1 : 0;
4680 height = lf.lfHeight;
4682 face = best = best_bitmap = NULL;
4683 font_link = find_font_link(family->FamilyName);
4684 face_list = get_face_list_from_family(family);
4685 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4687 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4688 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4693 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4694 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4695 new_score = (italic ^ it) + (bold ^ bd);
4696 if(!best || new_score <= score)
4698 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4699 italic, bold, it, bd);
4702 if(best->scalable && score == 0) break;
4706 newdiff = height - (signed int)(best->size.height);
4708 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4709 if(!best_bitmap || new_score < score ||
4710 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4712 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4715 if(score == 0 && diff == 0) break;
4722 face = best->scalable ? best : best_bitmap;
4723 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4724 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4727 height = lf.lfHeight;
4731 if(csi.fs.fsCsb[0]) {
4732 ret->charset = lf.lfCharSet;
4733 ret->codepage = csi.ciACP;
4736 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4738 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4739 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4741 ret->aveWidth = height ? lf.lfWidth : 0;
4743 if(!face->scalable) {
4744 /* Windows uses integer scaling factors for bitmap fonts */
4745 INT scale, scaled_height;
4746 GdiFont *cachedfont;
4748 /* FIXME: rotation of bitmap fonts is ignored */
4749 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4751 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4752 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4753 dcmat.eM11 = dcmat.eM22 = 1.0;
4754 /* As we changed the matrix, we need to search the cache for the font again,
4755 * otherwise we might explode the cache. */
4756 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4757 TRACE("Found cached font after non-scalable matrix rescale!\n");
4762 calc_hash(&ret->font_desc);
4764 if (height != 0) height = diff;
4765 height += face->size.height;
4767 scale = (height + face->size.height - 1) / face->size.height;
4768 scaled_height = scale * face->size.height;
4769 /* Only jump to the next height if the difference <= 25% original height */
4770 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4771 /* The jump between unscaled and doubled is delayed by 1 */
4772 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4773 ret->scale_y = scale;
4775 width = face->size.x_ppem >> 6;
4776 height = face->size.y_ppem >> 6;
4780 TRACE("font scale y: %f\n", ret->scale_y);
4782 ret->ft_face = OpenFontFace(ret, face, width, height);
4791 ret->ntmFlags = face->ntmFlags;
4793 if (ret->charset == SYMBOL_CHARSET &&
4794 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4797 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4801 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4804 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4805 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4806 ret->underline = lf.lfUnderline ? 0xff : 0;
4807 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4808 create_child_font_list(ret);
4810 if (face->vertical) /* We need to try to load the GSUB table */
4812 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4813 if (length != GDI_ERROR)
4815 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4816 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4817 TRACE("Loaded GSUB table of %i bytes\n",length);
4821 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4828 physdev->font = ret;
4830 LeaveCriticalSection( &freetype_cs );
4831 release_dc_ptr( dc );
4832 return ret ? hfont : 0;
4835 static void dump_gdi_font_list(void)
4838 struct list *elem_ptr;
4840 TRACE("---------- gdiFont Cache ----------\n");
4841 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4842 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4843 TRACE("gdiFont=%p %s %d\n",
4844 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4847 TRACE("---------- Unused gdiFont Cache ----------\n");
4848 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4849 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4850 TRACE("gdiFont=%p %s %d\n",
4851 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4854 TRACE("---------- Child gdiFont Cache ----------\n");
4855 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4856 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4857 TRACE("gdiFont=%p %s %d\n",
4858 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4862 /*************************************************************
4863 * WineEngDestroyFontInstance
4865 * free the gdiFont associated with this handle
4868 BOOL WineEngDestroyFontInstance(HFONT handle)
4873 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4877 EnterCriticalSection( &freetype_cs );
4879 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4881 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4882 while(hfontlist_elem_ptr) {
4883 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4884 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4885 if(hflist->hfont == handle) {
4886 TRACE("removing child font %p from child list\n", gdiFont);
4887 list_remove(&gdiFont->entry);
4888 LeaveCriticalSection( &freetype_cs );
4894 TRACE("destroying hfont=%p\n", handle);
4896 dump_gdi_font_list();
4898 font_elem_ptr = list_head(&gdi_font_list);
4899 while(font_elem_ptr) {
4900 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4901 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4903 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4904 while(hfontlist_elem_ptr) {
4905 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4906 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4907 if(hflist->hfont == handle) {
4908 list_remove(&hflist->entry);
4909 HeapFree(GetProcessHeap(), 0, hflist);
4913 if(list_empty(&gdiFont->hfontlist)) {
4914 TRACE("Moving to Unused list\n");
4915 list_remove(&gdiFont->entry);
4916 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4921 font_elem_ptr = list_head(&unused_gdi_font_list);
4922 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4923 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4924 while(font_elem_ptr) {
4925 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4926 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4927 TRACE("freeing %p\n", gdiFont);
4928 list_remove(&gdiFont->entry);
4931 LeaveCriticalSection( &freetype_cs );
4935 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4942 id += IDS_FIRST_SCRIPT;
4943 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4944 if (!rsrc) return 0;
4945 hMem = LoadResource( gdi32_module, rsrc );
4946 if (!hMem) return 0;
4948 p = LockResource( hMem );
4950 while (id--) p += *p + 1;
4952 i = min(LF_FACESIZE - 1, *p);
4953 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4959 /***************************************************
4960 * create_enum_charset_list
4962 * This function creates charset enumeration list because in DEFAULT_CHARSET
4963 * case, the ANSI codepage's charset takes precedence over other charsets.
4964 * This function works as a filter other than DEFAULT_CHARSET case.
4966 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4971 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4972 csi.fs.fsCsb[0] != 0) {
4973 list->element[n].mask = csi.fs.fsCsb[0];
4974 list->element[n].charset = csi.ciCharset;
4975 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4978 else { /* charset is DEFAULT_CHARSET or invalid. */
4981 /* Set the current codepage's charset as the first element. */
4983 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4984 csi.fs.fsCsb[0] != 0) {
4985 list->element[n].mask = csi.fs.fsCsb[0];
4986 list->element[n].charset = csi.ciCharset;
4987 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4991 /* Fill out left elements. */
4992 for (i = 0; i < 32; i++) {
4994 fs.fsCsb[0] = 1L << i;
4996 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4997 continue; /* skip, already added. */
4998 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4999 continue; /* skip, this is an invalid fsCsb bit. */
5001 list->element[n].mask = fs.fsCsb[0];
5002 list->element[n].charset = csi.ciCharset;
5003 load_script_name( i, list->element[n].name );
5012 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5013 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5018 if (face->cached_enum_data)
5021 *pelf = face->cached_enum_data->elf;
5022 *pntm = face->cached_enum_data->ntm;
5023 *ptype = face->cached_enum_data->type;
5027 font = alloc_font();
5029 if(face->scalable) {
5030 height = -2048; /* 2048 is the most common em size */
5033 height = face->size.y_ppem >> 6;
5034 width = face->size.x_ppem >> 6;
5036 font->scale_y = 1.0;
5038 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5044 font->name = strdupW(face->family->FamilyName);
5045 font->ntmFlags = face->ntmFlags;
5047 if (get_outline_text_metrics(font))
5049 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5051 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5053 lstrcpynW(pelf->elfLogFont.lfFaceName,
5054 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5056 lstrcpynW(pelf->elfFullName,
5057 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
5059 lstrcpynW(pelf->elfStyle,
5060 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5065 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5067 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5069 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5071 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5073 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5074 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5077 pntm->ntmTm.ntmFlags = face->ntmFlags;
5078 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5079 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5080 pntm->ntmFontSig = face->fs;
5082 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5084 pelf->elfLogFont.lfEscapement = 0;
5085 pelf->elfLogFont.lfOrientation = 0;
5086 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5087 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5088 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5089 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5090 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5091 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5092 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5093 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5094 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5095 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5096 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5099 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5100 *ptype |= TRUETYPE_FONTTYPE;
5101 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5102 *ptype |= DEVICE_FONTTYPE;
5103 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5104 *ptype |= RASTER_FONTTYPE;
5106 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5107 if (face->cached_enum_data)
5109 face->cached_enum_data->elf = *pelf;
5110 face->cached_enum_data->ntm = *pntm;
5111 face->cached_enum_data->type = *ptype;
5117 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
5119 static const WCHAR spaceW[] = { ' ', 0 };
5121 strcpyW(full_name, family_name);
5122 strcatW(full_name, spaceW);
5123 strcatW(full_name, style_name);
5126 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5128 const struct list *face_list, *face_elem_ptr;
5130 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5132 face_list = get_face_list_from_family(family);
5133 LIST_FOR_EACH(face_elem_ptr, face_list)
5135 WCHAR full_family_name[LF_FULLFACESIZE];
5136 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5138 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5140 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5141 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
5145 create_full_name(full_family_name, family->FamilyName, face->StyleName);
5146 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
5152 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5154 WCHAR full_family_name[LF_FULLFACESIZE];
5156 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5158 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5160 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5161 debugstr_w(family_name), debugstr_w(face->StyleName));
5165 create_full_name(full_family_name, family_name, face->StyleName);
5166 return !strcmpiW(lf->lfFaceName, full_family_name);
5169 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5170 FONTENUMPROCW proc, LPARAM lparam)
5173 NEWTEXTMETRICEXW ntm;
5177 GetEnumStructs(face, &elf, &ntm, &type);
5178 for(i = 0; i < list->total; i++) {
5179 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5180 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5181 load_script_name( IDS_OEM_DOS, elf.elfScript );
5182 i = list->total; /* break out of loop after enumeration */
5183 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
5186 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5187 strcpyW(elf.elfScript, list->element[i].name);
5188 if (!elf.elfScript[0])
5189 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5191 /* Font Replacement */
5192 if (family != face->family)
5194 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5195 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
5197 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5198 debugstr_w(elf.elfLogFont.lfFaceName),
5199 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5200 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5201 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5202 ntm.ntmTm.ntmFlags);
5203 /* release section before callback (FIXME) */
5204 LeaveCriticalSection( &freetype_cs );
5205 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5206 EnterCriticalSection( &freetype_cs );
5211 /*************************************************************
5212 * freetype_EnumFonts
5214 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5218 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5220 struct enum_charset_list enum_charsets;
5224 lf.lfCharSet = DEFAULT_CHARSET;
5225 lf.lfPitchAndFamily = 0;
5226 lf.lfFaceName[0] = 0;
5230 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5232 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5235 EnterCriticalSection( &freetype_cs );
5236 if(plf->lfFaceName[0]) {
5238 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5241 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5242 debugstr_w(psub->to.name));
5244 strcpyW(lf.lfFaceName, psub->to.name);
5248 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5249 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5250 if(family_matches(family, plf)) {
5251 face_list = get_face_list_from_family(family);
5252 LIST_FOR_EACH(face_elem_ptr, face_list) {
5253 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5254 if (!face_matches(family->FamilyName, face, plf)) continue;
5255 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5260 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5261 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5262 face_list = get_face_list_from_family(family);
5263 face_elem_ptr = list_head(face_list);
5264 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5265 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5268 LeaveCriticalSection( &freetype_cs );
5272 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5274 pt->x.value = vec->x >> 6;
5275 pt->x.fract = (vec->x & 0x3f) << 10;
5276 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5277 pt->y.value = vec->y >> 6;
5278 pt->y.fract = (vec->y & 0x3f) << 10;
5279 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5283 /***************************************************
5284 * According to the MSDN documentation on WideCharToMultiByte,
5285 * certain codepages cannot set the default_used parameter.
5286 * This returns TRUE if the codepage can set that parameter, false else
5287 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5289 static BOOL codepage_sets_default_used(UINT codepage)
5303 * GSUB Table handling functions
5306 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5308 const GSUB_CoverageFormat1* cf1;
5312 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5314 int count = GET_BE_WORD(cf1->GlyphCount);
5316 TRACE("Coverage Format 1, %i glyphs\n",count);
5317 for (i = 0; i < count; i++)
5318 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5322 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5324 const GSUB_CoverageFormat2* cf2;
5327 cf2 = (const GSUB_CoverageFormat2*)cf1;
5329 count = GET_BE_WORD(cf2->RangeCount);
5330 TRACE("Coverage Format 2, %i ranges\n",count);
5331 for (i = 0; i < count; i++)
5333 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5335 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5336 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5338 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5339 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5345 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5350 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5352 const GSUB_ScriptList *script;
5353 const GSUB_Script *deflt = NULL;
5355 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5357 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5358 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5360 const GSUB_Script *scr;
5363 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5364 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5366 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5368 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5374 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5378 const GSUB_LangSys *Lang;
5380 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5382 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5384 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5385 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5387 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5390 offset = GET_BE_WORD(script->DefaultLangSys);
5393 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5399 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5402 const GSUB_FeatureList *feature;
5403 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5405 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5406 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5408 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5409 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5411 const GSUB_Feature *feat;
5412 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5419 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5423 const GSUB_LookupList *lookup;
5424 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5426 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5427 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5429 const GSUB_LookupTable *look;
5430 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5431 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5432 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5433 if (GET_BE_WORD(look->LookupType) != 1)
5434 FIXME("We only handle SubType 1\n");
5439 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5441 const GSUB_SingleSubstFormat1 *ssf1;
5442 offset = GET_BE_WORD(look->SubTable[j]);
5443 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5444 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5446 int offset = GET_BE_WORD(ssf1->Coverage);
5447 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5448 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5450 TRACE(" Glyph 0x%x ->",glyph);
5451 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5452 TRACE(" 0x%x\n",glyph);
5457 const GSUB_SingleSubstFormat2 *ssf2;
5461 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5462 offset = GET_BE_WORD(ssf1->Coverage);
5463 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5464 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5465 TRACE(" Coverage index %i\n",index);
5468 TRACE(" Glyph is 0x%x ->",glyph);
5469 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5470 TRACE("0x%x\n",glyph);
5479 static const char* get_opentype_script(const GdiFont *font)
5482 * I am not sure if this is the correct way to generate our script tag
5485 switch (font->charset)
5487 case ANSI_CHARSET: return "latn";
5488 case BALTIC_CHARSET: return "latn"; /* ?? */
5489 case CHINESEBIG5_CHARSET: return "hani";
5490 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5491 case GB2312_CHARSET: return "hani";
5492 case GREEK_CHARSET: return "grek";
5493 case HANGUL_CHARSET: return "hang";
5494 case RUSSIAN_CHARSET: return "cyrl";
5495 case SHIFTJIS_CHARSET: return "kana";
5496 case TURKISH_CHARSET: return "latn"; /* ?? */
5497 case VIETNAMESE_CHARSET: return "latn";
5498 case JOHAB_CHARSET: return "latn"; /* ?? */
5499 case ARABIC_CHARSET: return "arab";
5500 case HEBREW_CHARSET: return "hebr";
5501 case THAI_CHARSET: return "thai";
5502 default: return "latn";
5506 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5508 const GSUB_Header *header;
5509 const GSUB_Script *script;
5510 const GSUB_LangSys *language;
5511 const GSUB_Feature *feature;
5513 if (!font->GSUB_Table)
5516 header = font->GSUB_Table;
5518 script = GSUB_get_script_table(header, get_opentype_script(font));
5521 TRACE("Script not found\n");
5524 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5527 TRACE("Language not found\n");
5530 feature = GSUB_get_feature(header, language, "vrt2");
5532 feature = GSUB_get_feature(header, language, "vert");
5535 TRACE("vrt2/vert feature not found\n");
5538 return GSUB_apply_feature(header, feature, glyph);
5541 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5545 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5546 WCHAR wc = (WCHAR)glyph;
5548 BOOL *default_used_pointer;
5551 default_used_pointer = NULL;
5552 default_used = FALSE;
5553 if (codepage_sets_default_used(font->codepage))
5554 default_used_pointer = &default_used;
5555 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5558 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5559 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5563 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5565 if (glyph < 0x100) glyph += 0xf000;
5566 /* there is a number of old pre-Unicode "broken" TTFs, which
5567 do have symbols at U+00XX instead of U+f0XX */
5568 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5569 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5571 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5576 /*************************************************************
5577 * freetype_GetGlyphIndices
5579 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5581 struct freetype_physdev *physdev = get_freetype_dev( dev );
5584 BOOL got_default = FALSE;
5588 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5589 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5592 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5594 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5599 EnterCriticalSection( &freetype_cs );
5601 for(i = 0; i < count; i++)
5603 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5608 if (FT_IS_SFNT(physdev->font->ft_face))
5610 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5611 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5616 get_text_metrics(physdev->font, &textm);
5617 default_char = textm.tmDefaultChar;
5621 pgi[i] = default_char;
5624 LeaveCriticalSection( &freetype_cs );
5628 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5630 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5631 return !memcmp(matrix, &identity, sizeof(FMAT2));
5634 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5636 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5637 return !memcmp(matrix, &identity, sizeof(MAT2));
5640 static inline BYTE get_max_level( UINT format )
5644 case GGO_GRAY2_BITMAP: return 4;
5645 case GGO_GRAY4_BITMAP: return 16;
5646 case GGO_GRAY8_BITMAP: return 64;
5651 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5653 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5654 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5657 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5658 FT_Face ft_face = incoming_font->ft_face;
5659 GdiFont *font = incoming_font;
5660 FT_UInt glyph_index;
5661 DWORD width, height, pitch, needed = 0;
5662 FT_Bitmap ft_bitmap;
5664 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5666 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5667 double widthRatio = 1.0;
5668 FT_Matrix transMat = identityMat;
5669 FT_Matrix transMatUnrotated;
5670 BOOL needsTransform = FALSE;
5671 BOOL tategaki = (font->GSUB_Table != NULL);
5672 UINT original_index;
5674 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5675 buflen, buf, lpmat);
5677 TRACE("font transform %f %f %f %f\n",
5678 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5679 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5681 if(format & GGO_GLYPH_INDEX) {
5682 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5683 original_index = glyph;
5684 format &= ~GGO_GLYPH_INDEX;
5686 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5687 ft_face = font->ft_face;
5688 original_index = glyph_index;
5691 if(format & GGO_UNHINTED) {
5692 load_flags |= FT_LOAD_NO_HINTING;
5693 format &= ~GGO_UNHINTED;
5696 /* tategaki never appears to happen to lower glyph index */
5697 if (glyph_index < TATEGAKI_LOWER_BOUND )
5700 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5701 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5702 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5703 font->gmsize * sizeof(GM*));
5705 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5706 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5708 *lpgm = FONT_GM(font,original_index)->gm;
5709 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5710 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5711 lpgm->gmCellIncX, lpgm->gmCellIncY);
5712 return 1; /* FIXME */
5716 if (!font->gm[original_index / GM_BLOCK_SIZE])
5717 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5719 /* Scaling factor */
5724 get_text_metrics(font, &tm);
5726 widthRatio = (double)font->aveWidth;
5727 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5730 widthRatio = font->scale_y;
5732 /* Scaling transform */
5733 if (widthRatio != 1.0 || font->scale_y != 1.0)
5736 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5739 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5741 pFT_Matrix_Multiply(&scaleMat, &transMat);
5742 needsTransform = TRUE;
5745 /* Slant transform */
5746 if (font->fake_italic) {
5749 slantMat.xx = (1 << 16);
5750 slantMat.xy = ((1 << 16) >> 2);
5752 slantMat.yy = (1 << 16);
5753 pFT_Matrix_Multiply(&slantMat, &transMat);
5754 needsTransform = TRUE;
5757 /* Rotation transform */
5758 transMatUnrotated = transMat;
5759 if(font->orientation && !tategaki) {
5760 FT_Matrix rotationMat;
5762 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5763 pFT_Vector_Unit(&vecAngle, angle);
5764 rotationMat.xx = vecAngle.x;
5765 rotationMat.xy = -vecAngle.y;
5766 rotationMat.yx = -rotationMat.xy;
5767 rotationMat.yy = rotationMat.xx;
5769 pFT_Matrix_Multiply(&rotationMat, &transMat);
5770 needsTransform = TRUE;
5773 /* World transform */
5774 if (!is_identity_FMAT2(&font->font_desc.matrix))
5777 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5778 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5779 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5780 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5781 pFT_Matrix_Multiply(&worldMat, &transMat);
5782 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5783 needsTransform = TRUE;
5786 /* Extra transformation specified by caller */
5787 if (!is_identity_MAT2(lpmat))
5790 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5791 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5792 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5793 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5794 pFT_Matrix_Multiply(&extraMat, &transMat);
5795 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5796 needsTransform = TRUE;
5799 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5800 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5801 format == GGO_GRAY8_BITMAP))
5803 load_flags |= FT_LOAD_NO_BITMAP;
5806 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5809 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5813 if(!needsTransform) {
5814 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5815 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5816 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5818 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5819 bottom = (ft_face->glyph->metrics.horiBearingY -
5820 ft_face->glyph->metrics.height) & -64;
5821 lpgm->gmCellIncX = adv;
5822 lpgm->gmCellIncY = 0;
5829 for(xc = 0; xc < 2; xc++) {
5830 for(yc = 0; yc < 2; yc++) {
5831 vec.x = (ft_face->glyph->metrics.horiBearingX +
5832 xc * ft_face->glyph->metrics.width);
5833 vec.y = ft_face->glyph->metrics.horiBearingY -
5834 yc * ft_face->glyph->metrics.height;
5835 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5836 pFT_Vector_Transform(&vec, &transMat);
5837 if(xc == 0 && yc == 0) {
5838 left = right = vec.x;
5839 top = bottom = vec.y;
5841 if(vec.x < left) left = vec.x;
5842 else if(vec.x > right) right = vec.x;
5843 if(vec.y < bottom) bottom = vec.y;
5844 else if(vec.y > top) top = vec.y;
5849 right = (right + 63) & -64;
5850 bottom = bottom & -64;
5851 top = (top + 63) & -64;
5853 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5854 vec.x = ft_face->glyph->metrics.horiAdvance;
5856 pFT_Vector_Transform(&vec, &transMat);
5857 lpgm->gmCellIncX = (vec.x+63) >> 6;
5858 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5860 vec.x = ft_face->glyph->metrics.horiAdvance;
5862 pFT_Vector_Transform(&vec, &transMatUnrotated);
5863 adv = (vec.x+63) >> 6;
5867 bbx = (right - left) >> 6;
5868 lpgm->gmBlackBoxX = (right - left) >> 6;
5869 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5870 lpgm->gmptGlyphOrigin.x = left >> 6;
5871 lpgm->gmptGlyphOrigin.y = top >> 6;
5873 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5874 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5875 lpgm->gmCellIncX, lpgm->gmCellIncY);
5877 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5878 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5880 FONT_GM(font,original_index)->gm = *lpgm;
5881 FONT_GM(font,original_index)->adv = adv;
5882 FONT_GM(font,original_index)->lsb = lsb;
5883 FONT_GM(font,original_index)->bbx = bbx;
5884 FONT_GM(font,original_index)->init = TRUE;
5887 if(format == GGO_METRICS)
5889 return 1; /* FIXME */
5892 if(ft_face->glyph->format != ft_glyph_format_outline &&
5893 (format == GGO_NATIVE || format == GGO_BEZIER))
5895 TRACE("loaded a bitmap\n");
5901 width = lpgm->gmBlackBoxX;
5902 height = lpgm->gmBlackBoxY;
5903 pitch = ((width + 31) >> 5) << 2;
5904 needed = pitch * height;
5906 if(!buf || !buflen) break;
5908 switch(ft_face->glyph->format) {
5909 case ft_glyph_format_bitmap:
5911 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5912 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5913 INT h = ft_face->glyph->bitmap.rows;
5915 memcpy(dst, src, w);
5916 src += ft_face->glyph->bitmap.pitch;
5922 case ft_glyph_format_outline:
5923 ft_bitmap.width = width;
5924 ft_bitmap.rows = height;
5925 ft_bitmap.pitch = pitch;
5926 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5927 ft_bitmap.buffer = buf;
5930 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5932 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5934 /* Note: FreeType will only set 'black' bits for us. */
5935 memset(buf, 0, needed);
5936 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5940 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5945 case GGO_GRAY2_BITMAP:
5946 case GGO_GRAY4_BITMAP:
5947 case GGO_GRAY8_BITMAP:
5948 case WINE_GGO_GRAY16_BITMAP:
5950 unsigned int max_level, row, col;
5953 width = lpgm->gmBlackBoxX;
5954 height = lpgm->gmBlackBoxY;
5955 pitch = (width + 3) / 4 * 4;
5956 needed = pitch * height;
5958 if(!buf || !buflen) break;
5960 max_level = get_max_level( format );
5962 switch(ft_face->glyph->format) {
5963 case ft_glyph_format_bitmap:
5965 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5966 INT h = ft_face->glyph->bitmap.rows;
5968 memset( buf, 0, needed );
5970 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5971 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5972 src += ft_face->glyph->bitmap.pitch;
5977 case ft_glyph_format_outline:
5979 ft_bitmap.width = width;
5980 ft_bitmap.rows = height;
5981 ft_bitmap.pitch = pitch;
5982 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5983 ft_bitmap.buffer = buf;
5986 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5988 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5990 memset(ft_bitmap.buffer, 0, buflen);
5992 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5994 if (max_level != 255)
5996 for (row = 0, start = buf; row < height; row++)
5998 for (col = 0, ptr = start; col < width; col++, ptr++)
5999 *ptr = (((int)*ptr) * max_level + 128) / 256;
6007 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6013 case WINE_GGO_HRGB_BITMAP:
6014 case WINE_GGO_HBGR_BITMAP:
6015 case WINE_GGO_VRGB_BITMAP:
6016 case WINE_GGO_VBGR_BITMAP:
6017 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6019 switch (ft_face->glyph->format)
6021 case FT_GLYPH_FORMAT_BITMAP:
6026 width = lpgm->gmBlackBoxX;
6027 height = lpgm->gmBlackBoxY;
6029 needed = pitch * height;
6031 if (!buf || !buflen) break;
6033 memset(buf, 0, buflen);
6035 src = ft_face->glyph->bitmap.buffer;
6036 src_pitch = ft_face->glyph->bitmap.pitch;
6038 height = min( height, ft_face->glyph->bitmap.rows );
6041 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6043 if ( src[x / 8] & masks[x % 8] )
6044 ((unsigned int *)dst)[x] = ~0u;
6053 case FT_GLYPH_FORMAT_OUTLINE:
6057 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6058 INT x_shift, y_shift;
6060 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6061 FT_Render_Mode render_mode =
6062 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6063 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6065 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6067 if ( render_mode == FT_RENDER_MODE_LCD)
6069 lpgm->gmBlackBoxX += 2;
6070 lpgm->gmptGlyphOrigin.x -= 1;
6074 lpgm->gmBlackBoxY += 2;
6075 lpgm->gmptGlyphOrigin.y += 1;
6079 width = lpgm->gmBlackBoxX;
6080 height = lpgm->gmBlackBoxY;
6082 needed = pitch * height;
6084 if (!buf || !buflen) break;
6086 memset(buf, 0, buflen);
6088 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6090 if ( needsTransform )
6091 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6093 if ( pFT_Library_SetLcdFilter )
6094 pFT_Library_SetLcdFilter( library, lcdfilter );
6095 pFT_Render_Glyph (ft_face->glyph, render_mode);
6097 src = ft_face->glyph->bitmap.buffer;
6098 src_pitch = ft_face->glyph->bitmap.pitch;
6099 src_width = ft_face->glyph->bitmap.width;
6100 src_height = ft_face->glyph->bitmap.rows;
6102 if ( render_mode == FT_RENDER_MODE_LCD)
6110 rgb_interval = src_pitch;
6115 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6116 if ( x_shift < 0 ) x_shift = 0;
6117 if ( x_shift + (src_width / hmul) > width )
6118 x_shift = width - (src_width / hmul);
6120 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6121 if ( y_shift < 0 ) y_shift = 0;
6122 if ( y_shift + (src_height / vmul) > height )
6123 y_shift = height - (src_height / vmul);
6125 dst += x_shift + y_shift * ( pitch / 4 );
6126 while ( src_height )
6128 for ( x = 0; x < src_width / hmul; x++ )
6132 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6133 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6134 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6135 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6139 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6140 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6141 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6142 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6145 src += src_pitch * vmul;
6154 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6166 int contour, point = 0, first_pt;
6167 FT_Outline *outline = &ft_face->glyph->outline;
6168 TTPOLYGONHEADER *pph;
6170 DWORD pph_start, cpfx, type;
6172 if(buflen == 0) buf = NULL;
6174 if (needsTransform && buf) {
6175 pFT_Outline_Transform(outline, &transMat);
6178 for(contour = 0; contour < outline->n_contours; contour++) {
6180 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6183 pph->dwType = TT_POLYGON_TYPE;
6184 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6186 needed += sizeof(*pph);
6188 while(point <= outline->contours[contour]) {
6189 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6190 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6191 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6195 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6198 } while(point <= outline->contours[contour] &&
6199 (outline->tags[point] & FT_Curve_Tag_On) ==
6200 (outline->tags[point-1] & FT_Curve_Tag_On));
6201 /* At the end of a contour Windows adds the start point, but
6203 if(point > outline->contours[contour] &&
6204 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6206 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6208 } else if(point <= outline->contours[contour] &&
6209 outline->tags[point] & FT_Curve_Tag_On) {
6210 /* add closing pt for bezier */
6212 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6220 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6223 pph->cb = needed - pph_start;
6229 /* Convert the quadratic Beziers to cubic Beziers.
6230 The parametric eqn for a cubic Bezier is, from PLRM:
6231 r(t) = at^3 + bt^2 + ct + r0
6232 with the control points:
6237 A quadratic Bezier has the form:
6238 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6240 So equating powers of t leads to:
6241 r1 = 2/3 p1 + 1/3 p0
6242 r2 = 2/3 p1 + 1/3 p2
6243 and of course r0 = p0, r3 = p2
6246 int contour, point = 0, first_pt;
6247 FT_Outline *outline = &ft_face->glyph->outline;
6248 TTPOLYGONHEADER *pph;
6250 DWORD pph_start, cpfx, type;
6251 FT_Vector cubic_control[4];
6252 if(buflen == 0) buf = NULL;
6254 if (needsTransform && buf) {
6255 pFT_Outline_Transform(outline, &transMat);
6258 for(contour = 0; contour < outline->n_contours; contour++) {
6260 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6263 pph->dwType = TT_POLYGON_TYPE;
6264 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6266 needed += sizeof(*pph);
6268 while(point <= outline->contours[contour]) {
6269 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6270 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6271 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6274 if(type == TT_PRIM_LINE) {
6276 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6280 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6283 /* FIXME: Possible optimization in endpoint calculation
6284 if there are two consecutive curves */
6285 cubic_control[0] = outline->points[point-1];
6286 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6287 cubic_control[0].x += outline->points[point].x + 1;
6288 cubic_control[0].y += outline->points[point].y + 1;
6289 cubic_control[0].x >>= 1;
6290 cubic_control[0].y >>= 1;
6292 if(point+1 > outline->contours[contour])
6293 cubic_control[3] = outline->points[first_pt];
6295 cubic_control[3] = outline->points[point+1];
6296 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6297 cubic_control[3].x += outline->points[point].x + 1;
6298 cubic_control[3].y += outline->points[point].y + 1;
6299 cubic_control[3].x >>= 1;
6300 cubic_control[3].y >>= 1;
6303 /* r1 = 1/3 p0 + 2/3 p1
6304 r2 = 1/3 p2 + 2/3 p1 */
6305 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6306 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6307 cubic_control[2] = cubic_control[1];
6308 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6309 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6310 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6311 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6313 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6314 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6315 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6320 } while(point <= outline->contours[contour] &&
6321 (outline->tags[point] & FT_Curve_Tag_On) ==
6322 (outline->tags[point-1] & FT_Curve_Tag_On));
6323 /* At the end of a contour Windows adds the start point,
6324 but only for Beziers and we've already done that.
6326 if(point <= outline->contours[contour] &&
6327 outline->tags[point] & FT_Curve_Tag_On) {
6328 /* This is the closing pt of a bezier, but we've already
6329 added it, so just inc point and carry on */
6336 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6339 pph->cb = needed - pph_start;
6345 FIXME("Unsupported format %d\n", format);
6351 static BOOL get_bitmap_text_metrics(GdiFont *font)
6353 FT_Face ft_face = font->ft_face;
6354 FT_WinFNT_HeaderRec winfnt_header;
6355 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6356 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6357 font->potm->otmSize = size;
6359 #define TM font->potm->otmTextMetrics
6360 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6362 TM.tmHeight = winfnt_header.pixel_height;
6363 TM.tmAscent = winfnt_header.ascent;
6364 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6365 TM.tmInternalLeading = winfnt_header.internal_leading;
6366 TM.tmExternalLeading = winfnt_header.external_leading;
6367 TM.tmAveCharWidth = winfnt_header.avg_width;
6368 TM.tmMaxCharWidth = winfnt_header.max_width;
6369 TM.tmWeight = winfnt_header.weight;
6371 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6372 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6373 TM.tmFirstChar = winfnt_header.first_char;
6374 TM.tmLastChar = winfnt_header.last_char;
6375 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6376 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6377 TM.tmItalic = winfnt_header.italic;
6378 TM.tmUnderlined = font->underline;
6379 TM.tmStruckOut = font->strikeout;
6380 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6381 TM.tmCharSet = winfnt_header.charset;
6385 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6386 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6387 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6388 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6389 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6390 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6391 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6392 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6394 TM.tmDigitizedAspectX = 96; /* FIXME */
6395 TM.tmDigitizedAspectY = 96; /* FIXME */
6397 TM.tmLastChar = 255;
6398 TM.tmDefaultChar = 32;
6399 TM.tmBreakChar = 32;
6400 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6401 TM.tmUnderlined = font->underline;
6402 TM.tmStruckOut = font->strikeout;
6403 /* NB inverted meaning of TMPF_FIXED_PITCH */
6404 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6405 TM.tmCharSet = font->charset;
6413 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6415 double scale_x, scale_y;
6419 scale_x = (double)font->aveWidth;
6420 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6423 scale_x = font->scale_y;
6425 scale_x *= fabs(font->font_desc.matrix.eM11);
6426 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6428 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6429 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6431 SCALE_Y(ptm->tmHeight);
6432 SCALE_Y(ptm->tmAscent);
6433 SCALE_Y(ptm->tmDescent);
6434 SCALE_Y(ptm->tmInternalLeading);
6435 SCALE_Y(ptm->tmExternalLeading);
6436 SCALE_Y(ptm->tmOverhang);
6438 SCALE_X(ptm->tmAveCharWidth);
6439 SCALE_X(ptm->tmMaxCharWidth);
6445 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6447 double scale_x, scale_y;
6451 scale_x = (double)font->aveWidth;
6452 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6455 scale_x = font->scale_y;
6457 scale_x *= fabs(font->font_desc.matrix.eM11);
6458 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6460 scale_font_metrics(font, &potm->otmTextMetrics);
6462 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6463 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6465 SCALE_Y(potm->otmAscent);
6466 SCALE_Y(potm->otmDescent);
6467 SCALE_Y(potm->otmLineGap);
6468 SCALE_Y(potm->otmsCapEmHeight);
6469 SCALE_Y(potm->otmsXHeight);
6470 SCALE_Y(potm->otmrcFontBox.top);
6471 SCALE_Y(potm->otmrcFontBox.bottom);
6472 SCALE_X(potm->otmrcFontBox.left);
6473 SCALE_X(potm->otmrcFontBox.right);
6474 SCALE_Y(potm->otmMacAscent);
6475 SCALE_Y(potm->otmMacDescent);
6476 SCALE_Y(potm->otmMacLineGap);
6477 SCALE_X(potm->otmptSubscriptSize.x);
6478 SCALE_Y(potm->otmptSubscriptSize.y);
6479 SCALE_X(potm->otmptSubscriptOffset.x);
6480 SCALE_Y(potm->otmptSubscriptOffset.y);
6481 SCALE_X(potm->otmptSuperscriptSize.x);
6482 SCALE_Y(potm->otmptSuperscriptSize.y);
6483 SCALE_X(potm->otmptSuperscriptOffset.x);
6484 SCALE_Y(potm->otmptSuperscriptOffset.y);
6485 SCALE_Y(potm->otmsStrikeoutSize);
6486 SCALE_Y(potm->otmsStrikeoutPosition);
6487 SCALE_Y(potm->otmsUnderscoreSize);
6488 SCALE_Y(potm->otmsUnderscorePosition);
6494 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6498 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6500 /* Make sure that the font has sane width/height ratio */
6503 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6505 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6510 *ptm = font->potm->otmTextMetrics;
6511 scale_font_metrics(font, ptm);
6515 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6519 for(i = 0; i < ft_face->num_charmaps; i++)
6521 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6527 static BOOL get_outline_text_metrics(GdiFont *font)
6530 FT_Face ft_face = font->ft_face;
6531 UINT needed, lenfam, lensty;
6533 TT_HoriHeader *pHori;
6534 TT_Postscript *pPost;
6535 FT_Fixed x_scale, y_scale;
6536 WCHAR *family_nameW, *style_nameW;
6537 static const WCHAR spaceW[] = {' ', '\0'};
6539 INT ascent, descent;
6541 TRACE("font=%p\n", font);
6543 if(!FT_IS_SCALABLE(ft_face))
6546 needed = sizeof(*font->potm);
6548 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6549 family_nameW = strdupW(font->name);
6551 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6553 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6554 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6555 style_nameW, lensty/sizeof(WCHAR));
6557 /* These names should be read from the TT name table */
6559 /* length of otmpFamilyName */
6562 /* length of otmpFaceName */
6563 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6564 needed += lenfam; /* just the family name */
6566 needed += lenfam + lensty; /* family + " " + style */
6569 /* length of otmpStyleName */
6572 /* length of otmpFullName */
6573 needed += lenfam + lensty;
6576 x_scale = ft_face->size->metrics.x_scale;
6577 y_scale = ft_face->size->metrics.y_scale;
6579 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6581 FIXME("Can't find OS/2 table - not TT font?\n");
6585 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6587 FIXME("Can't find HHEA table - not TT font?\n");
6591 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6593 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6594 pOS2->usWinAscent, pOS2->usWinDescent,
6595 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6596 ft_face->ascender, ft_face->descender, ft_face->height,
6597 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6598 ft_face->bbox.yMax, ft_face->bbox.yMin);
6600 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6601 font->potm->otmSize = needed;
6603 #define TM font->potm->otmTextMetrics
6605 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6606 ascent = pHori->Ascender;
6607 descent = -pHori->Descender;
6609 ascent = pOS2->usWinAscent;
6610 descent = pOS2->usWinDescent;
6614 TM.tmAscent = font->yMax;
6615 TM.tmDescent = -font->yMin;
6616 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6618 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6619 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6620 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6621 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6624 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6627 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6629 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6630 ((ascent + descent) -
6631 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6633 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6634 if (TM.tmAveCharWidth == 0) {
6635 TM.tmAveCharWidth = 1;
6637 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6638 TM.tmWeight = FW_REGULAR;
6639 if (font->fake_bold)
6640 TM.tmWeight = FW_BOLD;
6643 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6645 if (pOS2->usWeightClass > FW_MEDIUM)
6646 TM.tmWeight = pOS2->usWeightClass;
6648 else if (pOS2->usWeightClass <= FW_MEDIUM)
6649 TM.tmWeight = pOS2->usWeightClass;
6652 TM.tmDigitizedAspectX = 300;
6653 TM.tmDigitizedAspectY = 300;
6654 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6655 * symbol range to 0 - f0ff
6658 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6663 case 1257: /* Baltic */
6664 TM.tmLastChar = 0xf8fd;
6667 TM.tmLastChar = 0xf0ff;
6669 TM.tmBreakChar = 0x20;
6670 TM.tmDefaultChar = 0x1f;
6674 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6675 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6677 if(pOS2->usFirstCharIndex <= 1)
6678 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6679 else if (pOS2->usFirstCharIndex > 0xff)
6680 TM.tmBreakChar = 0x20;
6682 TM.tmBreakChar = pOS2->usFirstCharIndex;
6683 TM.tmDefaultChar = TM.tmBreakChar - 1;
6685 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6686 TM.tmUnderlined = font->underline;
6687 TM.tmStruckOut = font->strikeout;
6689 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6690 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6691 (pOS2->version == 0xFFFFU ||
6692 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6693 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6695 TM.tmPitchAndFamily = 0;
6697 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6699 case PAN_FAMILY_SCRIPT:
6700 TM.tmPitchAndFamily |= FF_SCRIPT;
6703 case PAN_FAMILY_DECORATIVE:
6704 TM.tmPitchAndFamily |= FF_DECORATIVE;
6709 case PAN_FAMILY_TEXT_DISPLAY:
6710 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6711 /* which is clearly not what the panose spec says. */
6713 if(TM.tmPitchAndFamily == 0 || /* fixed */
6714 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6715 TM.tmPitchAndFamily = FF_MODERN;
6718 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6723 TM.tmPitchAndFamily |= FF_DONTCARE;
6726 case PAN_SERIF_COVE:
6727 case PAN_SERIF_OBTUSE_COVE:
6728 case PAN_SERIF_SQUARE_COVE:
6729 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6730 case PAN_SERIF_SQUARE:
6731 case PAN_SERIF_THIN:
6732 case PAN_SERIF_BONE:
6733 case PAN_SERIF_EXAGGERATED:
6734 case PAN_SERIF_TRIANGLE:
6735 TM.tmPitchAndFamily |= FF_ROMAN;
6738 case PAN_SERIF_NORMAL_SANS:
6739 case PAN_SERIF_OBTUSE_SANS:
6740 case PAN_SERIF_PERP_SANS:
6741 case PAN_SERIF_FLARED:
6742 case PAN_SERIF_ROUNDED:
6743 TM.tmPitchAndFamily |= FF_SWISS;
6750 if(FT_IS_SCALABLE(ft_face))
6751 TM.tmPitchAndFamily |= TMPF_VECTOR;
6753 if(FT_IS_SFNT(ft_face))
6755 if (font->ntmFlags & NTM_PS_OPENTYPE)
6756 TM.tmPitchAndFamily |= TMPF_DEVICE;
6758 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6761 TM.tmCharSet = font->charset;
6763 font->potm->otmFiller = 0;
6764 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6765 font->potm->otmfsSelection = pOS2->fsSelection;
6766 font->potm->otmfsType = pOS2->fsType;
6767 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6768 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6769 font->potm->otmItalicAngle = 0; /* POST table */
6770 font->potm->otmEMSquare = ft_face->units_per_EM;
6771 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6772 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6773 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6774 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6775 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6776 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6777 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6778 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6779 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6780 font->potm->otmMacAscent = TM.tmAscent;
6781 font->potm->otmMacDescent = -TM.tmDescent;
6782 font->potm->otmMacLineGap = font->potm->otmLineGap;
6783 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6784 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6785 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6786 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6787 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6788 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6789 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6790 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6791 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6792 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6793 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6795 font->potm->otmsUnderscoreSize = 0;
6796 font->potm->otmsUnderscorePosition = 0;
6798 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6799 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6803 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6804 cp = (char*)font->potm + sizeof(*font->potm);
6805 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6806 strcpyW((WCHAR*)cp, family_nameW);
6808 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6809 strcpyW((WCHAR*)cp, style_nameW);
6811 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6812 strcpyW((WCHAR*)cp, family_nameW);
6813 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6814 strcatW((WCHAR*)cp, spaceW);
6815 strcatW((WCHAR*)cp, style_nameW);
6816 cp += lenfam + lensty;
6819 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6820 strcpyW((WCHAR*)cp, family_nameW);
6821 strcatW((WCHAR*)cp, spaceW);
6822 strcatW((WCHAR*)cp, style_nameW);
6826 HeapFree(GetProcessHeap(), 0, style_nameW);
6827 HeapFree(GetProcessHeap(), 0, family_nameW);
6831 /*************************************************************
6832 * freetype_GetGlyphOutline
6834 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6835 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6837 struct freetype_physdev *physdev = get_freetype_dev( dev );
6842 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6843 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6847 EnterCriticalSection( &freetype_cs );
6848 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6849 LeaveCriticalSection( &freetype_cs );
6853 /*************************************************************
6854 * freetype_GetTextMetrics
6856 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6858 struct freetype_physdev *physdev = get_freetype_dev( dev );
6863 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6864 return dev->funcs->pGetTextMetrics( dev, metrics );
6868 EnterCriticalSection( &freetype_cs );
6869 ret = get_text_metrics( physdev->font, metrics );
6870 LeaveCriticalSection( &freetype_cs );
6874 /*************************************************************
6875 * freetype_GetOutlineTextMetrics
6877 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6879 struct freetype_physdev *physdev = get_freetype_dev( dev );
6884 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6885 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6888 TRACE("font=%p\n", physdev->font);
6890 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6893 EnterCriticalSection( &freetype_cs );
6895 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6897 if(cbSize >= physdev->font->potm->otmSize)
6899 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6900 scale_outline_font_metrics(physdev->font, potm);
6902 ret = physdev->font->potm->otmSize;
6904 LeaveCriticalSection( &freetype_cs );
6908 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6910 HFONTLIST *hfontlist;
6911 child->font = alloc_font();
6912 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6913 if(!child->font->ft_face)
6915 free_font(child->font);
6920 child->font->font_desc = font->font_desc;
6921 child->font->ntmFlags = child->face->ntmFlags;
6922 child->font->orientation = font->orientation;
6923 child->font->scale_y = font->scale_y;
6924 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6925 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6926 child->font->name = strdupW(child->face->family->FamilyName);
6927 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6928 child->font->base_font = font;
6929 list_add_head(&child_font_list, &child->font->entry);
6930 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6934 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6937 CHILD_FONT *child_font;
6940 font = font->base_font;
6942 *linked_font = font;
6944 if((*glyph = get_glyph_index(font, c)))
6946 *glyph = get_GSUB_vert_glyph(font, *glyph);
6950 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6952 if(!child_font->font)
6953 if(!load_child_font(font, child_font))
6956 if(!child_font->font->ft_face)
6958 g = get_glyph_index(child_font->font, c);
6959 g = get_GSUB_vert_glyph(child_font->font, g);
6963 *linked_font = child_font->font;
6970 /*************************************************************
6971 * freetype_GetCharWidth
6973 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6975 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6978 FT_UInt glyph_index;
6979 GdiFont *linked_font;
6980 struct freetype_physdev *physdev = get_freetype_dev( dev );
6984 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6985 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6988 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6991 EnterCriticalSection( &freetype_cs );
6992 for(c = firstChar; c <= lastChar; c++) {
6993 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6994 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6995 &gm, 0, NULL, &identity);
6996 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6998 LeaveCriticalSection( &freetype_cs );
7002 /*************************************************************
7003 * freetype_GetCharABCWidths
7005 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7007 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7010 FT_UInt glyph_index;
7011 GdiFont *linked_font;
7012 struct freetype_physdev *physdev = get_freetype_dev( dev );
7016 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7017 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7020 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7023 EnterCriticalSection( &freetype_cs );
7025 for(c = firstChar; c <= lastChar; c++) {
7026 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7027 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7028 &gm, 0, NULL, &identity);
7029 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
7030 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
7031 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
7032 FONT_GM(linked_font,glyph_index)->bbx;
7034 LeaveCriticalSection( &freetype_cs );
7038 /*************************************************************
7039 * freetype_GetCharABCWidthsI
7041 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7043 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7046 FT_UInt glyph_index;
7047 GdiFont *linked_font;
7048 struct freetype_physdev *physdev = get_freetype_dev( dev );
7052 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7053 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7056 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7060 EnterCriticalSection( &freetype_cs );
7062 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
7064 for(c = firstChar; c < firstChar+count; c++) {
7065 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
7066 &gm, 0, NULL, &identity);
7067 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
7068 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
7069 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
7070 - FONT_GM(linked_font,c)->bbx;
7073 for(c = 0; c < count; c++) {
7074 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
7075 &gm, 0, NULL, &identity);
7076 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
7077 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
7078 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
7079 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
7082 LeaveCriticalSection( &freetype_cs );
7086 /*************************************************************
7087 * freetype_GetTextExtentExPoint
7089 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7090 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7092 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7097 FT_UInt glyph_index;
7098 GdiFont *linked_font;
7099 struct freetype_physdev *physdev = get_freetype_dev( dev );
7103 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7104 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7107 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7110 EnterCriticalSection( &freetype_cs );
7113 get_text_metrics( physdev->font, &tm );
7114 size->cy = tm.tmHeight;
7116 for(idx = 0; idx < count; idx++) {
7117 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7118 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7119 &gm, 0, NULL, &identity);
7120 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7122 if (! pnfit || ext <= max_ext) {
7132 LeaveCriticalSection( &freetype_cs );
7133 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7137 /*************************************************************
7138 * freetype_GetTextExtentExPointI
7140 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7141 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7143 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7148 struct freetype_physdev *physdev = get_freetype_dev( dev );
7152 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7153 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7156 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7159 EnterCriticalSection( &freetype_cs );
7162 get_text_metrics(physdev->font, &tm);
7163 size->cy = tm.tmHeight;
7165 for(idx = 0; idx < count; idx++) {
7166 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7167 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7169 if (! pnfit || ext <= max_ext) {
7179 LeaveCriticalSection( &freetype_cs );
7180 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7184 /*************************************************************
7185 * freetype_GetFontData
7187 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7189 struct freetype_physdev *physdev = get_freetype_dev( dev );
7193 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7194 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7197 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7198 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7199 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7201 return get_font_data( physdev->font, table, offset, buf, cbData );
7204 /*************************************************************
7205 * freetype_GetTextFace
7207 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7210 struct freetype_physdev *physdev = get_freetype_dev( dev );
7214 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7215 return dev->funcs->pGetTextFace( dev, count, str );
7218 n = strlenW(physdev->font->name) + 1;
7221 lstrcpynW(str, physdev->font->name, count);
7227 /*************************************************************
7228 * freetype_GetTextCharsetInfo
7230 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7232 struct freetype_physdev *physdev = get_freetype_dev( dev );
7236 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7237 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7239 if (fs) *fs = physdev->font->fs;
7240 return physdev->font->charset;
7243 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7245 GdiFont *font = dc->gdiFont, *linked_font;
7246 struct list *first_hfont;
7250 EnterCriticalSection( &freetype_cs );
7251 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7252 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7253 if(font == linked_font)
7254 *new_hfont = dc->hFont;
7257 first_hfont = list_head(&linked_font->hfontlist);
7258 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7260 LeaveCriticalSection( &freetype_cs );
7264 /* Retrieve a list of supported Unicode ranges for a given font.
7265 * Can be called with NULL gs to calculate the buffer size. Returns
7266 * the number of ranges found.
7268 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7270 DWORD num_ranges = 0;
7272 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7275 FT_ULong char_code, char_code_prev;
7278 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7280 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7281 face->num_glyphs, glyph_code, char_code);
7283 if (!glyph_code) return 0;
7287 gs->ranges[0].wcLow = (USHORT)char_code;
7288 gs->ranges[0].cGlyphs = 0;
7289 gs->cGlyphsSupported = 0;
7295 if (char_code < char_code_prev)
7297 ERR("expected increasing char code from FT_Get_Next_Char\n");
7300 if (char_code - char_code_prev > 1)
7305 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7306 gs->ranges[num_ranges - 1].cGlyphs = 1;
7307 gs->cGlyphsSupported++;
7312 gs->ranges[num_ranges - 1].cGlyphs++;
7313 gs->cGlyphsSupported++;
7315 char_code_prev = char_code;
7316 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7320 FIXME("encoding %u not supported\n", face->charmap->encoding);
7325 /*************************************************************
7326 * freetype_GetFontUnicodeRanges
7328 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7330 struct freetype_physdev *physdev = get_freetype_dev( dev );
7331 DWORD size, num_ranges;
7335 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7336 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7339 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7340 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7343 glyphset->cbThis = size;
7344 glyphset->cRanges = num_ranges;
7345 glyphset->flAccel = 0;
7350 /*************************************************************
7351 * freetype_FontIsLinked
7353 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7355 struct freetype_physdev *physdev = get_freetype_dev( dev );
7360 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7361 return dev->funcs->pFontIsLinked( dev );
7365 EnterCriticalSection( &freetype_cs );
7366 ret = !list_empty(&physdev->font->child_fonts);
7367 LeaveCriticalSection( &freetype_cs );
7371 static BOOL is_hinting_enabled(void)
7373 /* Use the >= 2.2.0 function if available */
7374 if(pFT_Get_TrueType_Engine_Type)
7376 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
7377 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
7379 #ifdef FT_DRIVER_HAS_HINTER
7384 /* otherwise if we've been compiled with < 2.2.0 headers
7385 use the internal macro */
7386 mod = pFT_Get_Module(library, "truetype");
7387 if(mod && FT_DRIVER_HAS_HINTER(mod))
7395 static BOOL is_subpixel_rendering_enabled( void )
7397 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7398 return pFT_Library_SetLcdFilter &&
7399 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7405 /*************************************************************************
7406 * GetRasterizerCaps (GDI32.@)
7408 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7410 static int hinting = -1;
7411 static int subpixel = -1;
7415 hinting = is_hinting_enabled();
7416 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7419 if ( subpixel == -1 )
7421 subpixel = is_subpixel_rendering_enabled();
7422 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7425 lprs->nSize = sizeof(RASTERIZER_STATUS);
7426 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7428 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7429 lprs->nLanguageID = 0;
7433 /*************************************************************
7434 * freetype_GdiRealizationInfo
7436 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7438 struct freetype_physdev *physdev = get_freetype_dev( dev );
7439 realization_info_t *info = ptr;
7443 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7444 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7447 FIXME("(%p, %p): stub!\n", physdev->font, info);
7450 if(FT_IS_SCALABLE(physdev->font->ft_face))
7453 info->cache_num = physdev->font->cache_num;
7454 info->unknown2 = -1;
7458 /*************************************************************************
7459 * Kerning support for TrueType fonts
7461 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7463 struct TT_kern_table
7469 struct TT_kern_subtable
7478 USHORT horizontal : 1;
7480 USHORT cross_stream: 1;
7481 USHORT override : 1;
7482 USHORT reserved1 : 4;
7488 struct TT_format0_kern_subtable
7492 USHORT entrySelector;
7503 static DWORD parse_format0_kern_subtable(GdiFont *font,
7504 const struct TT_format0_kern_subtable *tt_f0_ks,
7505 const USHORT *glyph_to_char,
7506 KERNINGPAIR *kern_pair, DWORD cPairs)
7509 const struct TT_kern_pair *tt_kern_pair;
7511 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7513 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7515 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7516 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7517 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7519 if (!kern_pair || !cPairs)
7522 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7524 nPairs = min(nPairs, cPairs);
7526 for (i = 0; i < nPairs; i++)
7528 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7529 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7530 /* this algorithm appears to better match what Windows does */
7531 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7532 if (kern_pair->iKernAmount < 0)
7534 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7535 kern_pair->iKernAmount -= font->ppem;
7537 else if (kern_pair->iKernAmount > 0)
7539 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7540 kern_pair->iKernAmount += font->ppem;
7542 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7544 TRACE("left %u right %u value %d\n",
7545 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7549 TRACE("copied %u entries\n", nPairs);
7553 /*************************************************************
7554 * freetype_GetKerningPairs
7556 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7560 const struct TT_kern_table *tt_kern_table;
7561 const struct TT_kern_subtable *tt_kern_subtable;
7563 USHORT *glyph_to_char;
7565 struct freetype_physdev *physdev = get_freetype_dev( dev );
7567 if (!(font = physdev->font))
7569 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7570 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7574 EnterCriticalSection( &freetype_cs );
7575 if (font->total_kern_pairs != (DWORD)-1)
7577 if (cPairs && kern_pair)
7579 cPairs = min(cPairs, font->total_kern_pairs);
7580 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7582 else cPairs = font->total_kern_pairs;
7584 LeaveCriticalSection( &freetype_cs );
7588 font->total_kern_pairs = 0;
7590 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7592 if (length == GDI_ERROR)
7594 TRACE("no kerning data in the font\n");
7595 LeaveCriticalSection( &freetype_cs );
7599 buf = HeapAlloc(GetProcessHeap(), 0, length);
7602 WARN("Out of memory\n");
7603 LeaveCriticalSection( &freetype_cs );
7607 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7609 /* build a glyph index to char code map */
7610 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7613 WARN("Out of memory allocating a glyph index to char code map\n");
7614 HeapFree(GetProcessHeap(), 0, buf);
7615 LeaveCriticalSection( &freetype_cs );
7619 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7625 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7627 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7628 font->ft_face->num_glyphs, glyph_code, char_code);
7632 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7634 /* FIXME: This doesn't match what Windows does: it does some fancy
7635 * things with duplicate glyph index to char code mappings, while
7636 * we just avoid overriding existing entries.
7638 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7639 glyph_to_char[glyph_code] = (USHORT)char_code;
7641 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7648 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7649 for (n = 0; n <= 65535; n++)
7650 glyph_to_char[n] = (USHORT)n;
7653 tt_kern_table = buf;
7654 nTables = GET_BE_WORD(tt_kern_table->nTables);
7655 TRACE("version %u, nTables %u\n",
7656 GET_BE_WORD(tt_kern_table->version), nTables);
7658 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7660 for (i = 0; i < nTables; i++)
7662 struct TT_kern_subtable tt_kern_subtable_copy;
7664 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7665 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7666 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7668 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7669 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7670 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7672 /* According to the TrueType specification this is the only format
7673 * that will be properly interpreted by Windows and OS/2
7675 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7677 DWORD new_chunk, old_total = font->total_kern_pairs;
7679 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7680 glyph_to_char, NULL, 0);
7681 font->total_kern_pairs += new_chunk;
7683 if (!font->kern_pairs)
7684 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7685 font->total_kern_pairs * sizeof(*font->kern_pairs));
7687 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7688 font->total_kern_pairs * sizeof(*font->kern_pairs));
7690 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7691 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7694 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7696 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7699 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7700 HeapFree(GetProcessHeap(), 0, buf);
7702 if (cPairs && kern_pair)
7704 cPairs = min(cPairs, font->total_kern_pairs);
7705 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7707 else cPairs = font->total_kern_pairs;
7709 LeaveCriticalSection( &freetype_cs );
7713 static const struct gdi_dc_funcs freetype_funcs =
7715 NULL, /* pAbortDoc */
7716 NULL, /* pAbortPath */
7717 NULL, /* pAlphaBlend */
7718 NULL, /* pAngleArc */
7721 NULL, /* pBeginPath */
7722 NULL, /* pBlendImage */
7723 NULL, /* pChoosePixelFormat */
7725 NULL, /* pCloseFigure */
7726 NULL, /* pCopyBitmap */
7727 NULL, /* pCreateBitmap */
7728 NULL, /* pCreateCompatibleDC */
7729 freetype_CreateDC, /* pCreateDC */
7730 NULL, /* pDeleteBitmap */
7731 freetype_DeleteDC, /* pDeleteDC */
7732 NULL, /* pDeleteObject */
7733 NULL, /* pDescribePixelFormat */
7734 NULL, /* pDeviceCapabilities */
7735 NULL, /* pEllipse */
7737 NULL, /* pEndPage */
7738 NULL, /* pEndPath */
7739 freetype_EnumFonts, /* pEnumFonts */
7740 NULL, /* pEnumICMProfiles */
7741 NULL, /* pExcludeClipRect */
7742 NULL, /* pExtDeviceMode */
7743 NULL, /* pExtEscape */
7744 NULL, /* pExtFloodFill */
7745 NULL, /* pExtSelectClipRgn */
7746 NULL, /* pExtTextOut */
7747 NULL, /* pFillPath */
7748 NULL, /* pFillRgn */
7749 NULL, /* pFlattenPath */
7750 freetype_FontIsLinked, /* pFontIsLinked */
7751 NULL, /* pFrameRgn */
7752 NULL, /* pGdiComment */
7753 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7754 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7755 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7756 freetype_GetCharWidth, /* pGetCharWidth */
7757 NULL, /* pGetDeviceCaps */
7758 NULL, /* pGetDeviceGammaRamp */
7759 freetype_GetFontData, /* pGetFontData */
7760 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7761 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7762 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7763 NULL, /* pGetICMProfile */
7764 NULL, /* pGetImage */
7765 freetype_GetKerningPairs, /* pGetKerningPairs */
7766 NULL, /* pGetNearestColor */
7767 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7768 NULL, /* pGetPixel */
7769 NULL, /* pGetPixelFormat */
7770 NULL, /* pGetSystemPaletteEntries */
7771 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7772 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7773 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7774 freetype_GetTextFace, /* pGetTextFace */
7775 freetype_GetTextMetrics, /* pGetTextMetrics */
7776 NULL, /* pGradientFill */
7777 NULL, /* pIntersectClipRect */
7778 NULL, /* pInvertRgn */
7780 NULL, /* pModifyWorldTransform */
7782 NULL, /* pOffsetClipRgn */
7783 NULL, /* pOffsetViewportOrg */
7784 NULL, /* pOffsetWindowOrg */
7785 NULL, /* pPaintRgn */
7788 NULL, /* pPolyBezier */
7789 NULL, /* pPolyBezierTo */
7790 NULL, /* pPolyDraw */
7791 NULL, /* pPolyPolygon */
7792 NULL, /* pPolyPolyline */
7793 NULL, /* pPolygon */
7794 NULL, /* pPolyline */
7795 NULL, /* pPolylineTo */
7796 NULL, /* pPutImage */
7797 NULL, /* pRealizeDefaultPalette */
7798 NULL, /* pRealizePalette */
7799 NULL, /* pRectangle */
7800 NULL, /* pResetDC */
7801 NULL, /* pRestoreDC */
7802 NULL, /* pRoundRect */
7804 NULL, /* pScaleViewportExt */
7805 NULL, /* pScaleWindowExt */
7806 NULL, /* pSelectBitmap */
7807 NULL, /* pSelectBrush */
7808 NULL, /* pSelectClipPath */
7809 freetype_SelectFont, /* pSelectFont */
7810 NULL, /* pSelectPalette */
7811 NULL, /* pSelectPen */
7812 NULL, /* pSetArcDirection */
7813 NULL, /* pSetBkColor */
7814 NULL, /* pSetBkMode */
7815 NULL, /* pSetDCBrushColor */
7816 NULL, /* pSetDCPenColor */
7817 NULL, /* pSetDIBColorTable */
7818 NULL, /* pSetDIBitsToDevice */
7819 NULL, /* pSetDeviceClipping */
7820 NULL, /* pSetDeviceGammaRamp */
7821 NULL, /* pSetLayout */
7822 NULL, /* pSetMapMode */
7823 NULL, /* pSetMapperFlags */
7824 NULL, /* pSetPixel */
7825 NULL, /* pSetPixelFormat */
7826 NULL, /* pSetPolyFillMode */
7827 NULL, /* pSetROP2 */
7828 NULL, /* pSetRelAbs */
7829 NULL, /* pSetStretchBltMode */
7830 NULL, /* pSetTextAlign */
7831 NULL, /* pSetTextCharacterExtra */
7832 NULL, /* pSetTextColor */
7833 NULL, /* pSetTextJustification */
7834 NULL, /* pSetViewportExt */
7835 NULL, /* pSetViewportOrg */
7836 NULL, /* pSetWindowExt */
7837 NULL, /* pSetWindowOrg */
7838 NULL, /* pSetWorldTransform */
7839 NULL, /* pStartDoc */
7840 NULL, /* pStartPage */
7841 NULL, /* pStretchBlt */
7842 NULL, /* pStretchDIBits */
7843 NULL, /* pStrokeAndFillPath */
7844 NULL, /* pStrokePath */
7845 NULL, /* pSwapBuffers */
7846 NULL, /* pUnrealizePalette */
7847 NULL, /* pWidenPath */
7848 /* OpenGL not supported */
7851 #else /* HAVE_FREETYPE */
7853 /*************************************************************************/
7855 BOOL WineEngInit(void)
7859 BOOL WineEngDestroyFontInstance(HFONT hfont)
7864 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7866 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7870 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7872 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7876 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7878 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7882 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7883 LPCWSTR font_file, LPCWSTR font_path )
7889 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7894 /*************************************************************************
7895 * GetRasterizerCaps (GDI32.@)
7897 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7899 lprs->nSize = sizeof(RASTERIZER_STATUS);
7901 lprs->nLanguageID = 0;
7905 #endif /* HAVE_FREETYPE */