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>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
60 #undef GetCurrentThread
63 #undef GetCurrentProcess
76 #endif /* HAVE_CARBON_CARBON_H */
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font
);
93 #ifdef HAVE_FT2BUILD_H
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType
;
143 static FT_Library library
= 0;
150 static FT_Version_t FT_Version
;
151 static DWORD FT_SimpleVersion
;
153 static void *ft_handle
= NULL
;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit
);
157 MAKE_FUNCPTR(FT_Done_Face
);
158 MAKE_FUNCPTR(FT_Get_Char_Index
);
159 MAKE_FUNCPTR(FT_Get_Module
);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
163 MAKE_FUNCPTR(FT_Init_FreeType
);
164 MAKE_FUNCPTR(FT_Load_Glyph
);
165 MAKE_FUNCPTR(FT_Matrix_Multiply
);
166 MAKE_FUNCPTR(FT_MulFix
);
167 MAKE_FUNCPTR(FT_New_Face
);
168 MAKE_FUNCPTR(FT_New_Memory_Face
);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
170 MAKE_FUNCPTR(FT_Outline_Transform
);
171 MAKE_FUNCPTR(FT_Outline_Translate
);
172 MAKE_FUNCPTR(FT_Select_Charmap
);
173 MAKE_FUNCPTR(FT_Set_Charmap
);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
175 MAKE_FUNCPTR(FT_Vector_Transform
);
176 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
177 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
178 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
179 static FT_ULong (*pFT_Get_Next_Char
)(FT_Face
,FT_ULong
,FT_UInt
*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent
);
188 MAKE_FUNCPTR(FcFontList
);
189 MAKE_FUNCPTR(FcFontSetDestroy
);
190 MAKE_FUNCPTR(FcInit
);
191 MAKE_FUNCPTR(FcObjectSetAdd
);
192 MAKE_FUNCPTR(FcObjectSetCreate
);
193 MAKE_FUNCPTR(FcObjectSetDestroy
);
194 MAKE_FUNCPTR(FcPatternCreate
);
195 MAKE_FUNCPTR(FcPatternDestroy
);
196 MAKE_FUNCPTR(FcPatternGetBool
);
197 MAKE_FUNCPTR(FcPatternGetString
);
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
227 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
234 FT_Short internal_leading
;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
241 FT_Short height
, width
;
242 FT_Pos size
, x_ppem
, y_ppem
;
248 NEWTEXTMETRICEXW ntm
;
252 typedef struct tagFace
{
257 DWORD font_data_size
;
262 FONTSIGNATURE fs_links
;
263 DWORD ntmFlags
; /* Only some bits stored here. Others are computed on the fly */
264 FT_Fixed font_version
;
266 Bitmap_Size size
; /* set if face is a bitmap */
267 BOOL external
; /* TRUE if we should manually add this font to the registry */
268 struct tagFamily
*family
;
269 /* Cached data for Enum */
270 struct enum_data
*cached_enum_data
;
273 typedef struct tagFamily
{
275 const WCHAR
*FamilyName
;
281 INT adv
; /* These three hold to widths of the unrotated chars */
299 typedef struct tagHFONTLIST
{
314 struct list hfontlist
;
315 OUTLINETEXTMETRICW
*potm
;
316 DWORD total_kern_pairs
;
317 KERNINGPAIR
*kern_pairs
;
318 struct list child_fonts
;
320 /* the following members can be accessed without locking, they are never modified after creation */
322 struct font_mapping
*mapping
;
344 const WCHAR
*font_name
;
348 #define GM_BLOCK_SIZE 128
349 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
351 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
352 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
353 #define UNUSED_CACHE_SIZE 10
354 static struct list child_font_list
= LIST_INIT(child_font_list
);
355 static struct list system_links
= LIST_INIT(system_links
);
357 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
359 static struct list font_list
= LIST_INIT(font_list
);
361 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
362 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
363 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
365 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
367 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
368 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
369 'W','i','n','d','o','w','s','\\',
370 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
371 'F','o','n','t','s','\0'};
373 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
374 'W','i','n','d','o','w','s',' ','N','T','\\',
375 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
376 'F','o','n','t','s','\0'};
378 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
379 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
380 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
381 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
383 static const WCHAR
* const SystemFontValues
[4] = {
390 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
391 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
393 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
394 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
395 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
396 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
397 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
398 'E','u','r','o','p','e','a','n','\0'};
399 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
400 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
401 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
402 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
403 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
404 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
405 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
406 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
407 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
408 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
409 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
410 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
412 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
422 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
430 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
439 typedef struct tagFontSubst
{
455 static struct list mappings_list
= LIST_INIT( mappings_list
);
457 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
459 static CRITICAL_SECTION freetype_cs
;
460 static CRITICAL_SECTION_DEBUG critsect_debug
=
463 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
464 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
466 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
468 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
470 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
471 static BOOL use_default_fallback
= FALSE
;
473 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
475 /****************************************
476 * Notes on .fon files
478 * The fonts System, FixedSys and Terminal are special. There are typically multiple
479 * versions installed for different resolutions and codepages. Windows stores which one to use
480 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
482 * FIXEDFON.FON FixedSys
484 * OEMFONT.FON Terminal
485 * LogPixels Current dpi set by the display control panel applet
486 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
487 * also has a LogPixels value that appears to mirror this)
489 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
490 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
491 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
492 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
493 * so that makes sense.
495 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
496 * to be mapped into the registry on Windows 2000 at least).
499 * ega80woa.fon=ega80850.fon
500 * ega40woa.fon=ega40850.fon
501 * cga80woa.fon=cga80850.fon
502 * cga40woa.fon=cga40850.fon
505 /* These are all structures needed for the GSUB table */
507 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
508 #define TATEGAKI_LOWER_BOUND 0x02F1
524 GSUB_ScriptRecord ScriptRecord
[1];
530 } GSUB_LangSysRecord
;
535 GSUB_LangSysRecord LangSysRecord
[1];
539 WORD LookupOrder
; /* Reserved */
540 WORD ReqFeatureIndex
;
542 WORD FeatureIndex
[1];
548 } GSUB_FeatureRecord
;
552 GSUB_FeatureRecord FeatureRecord
[1];
556 WORD FeatureParams
; /* Reserved */
558 WORD LookupListIndex
[1];
577 } GSUB_CoverageFormat1
;
582 WORD StartCoverageIndex
;
588 GSUB_RangeRecord RangeRecord
[1];
589 } GSUB_CoverageFormat2
;
592 WORD SubstFormat
; /* = 1 */
595 } GSUB_SingleSubstFormat1
;
598 WORD SubstFormat
; /* = 2 */
602 }GSUB_SingleSubstFormat2
;
604 #ifdef HAVE_CARBON_CARBON_H
605 static char *find_cache_dir(void)
609 static char cached_path
[MAX_PATH
];
610 static const char *wine
= "/Wine", *fonts
= "/Fonts";
612 if(*cached_path
) return cached_path
;
614 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
617 WARN("can't create cached data folder\n");
620 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
623 WARN("can't create cached data path\n");
627 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
629 ERR("Could not create full path\n");
633 strcat(cached_path
, wine
);
635 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
637 WARN("Couldn't mkdir %s\n", cached_path
);
641 strcat(cached_path
, fonts
);
642 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
644 WARN("Couldn't mkdir %s\n", cached_path
);
651 /******************************************************************
654 * Extracts individual TrueType font files from a Mac suitcase font
655 * and saves them into the user's caches directory (see
657 * Returns a NULL terminated array of filenames.
659 * We do this because they are apps that try to read ttf files
660 * themselves and they don't like Mac suitcase files.
662 static char **expand_mac_font(const char *path
)
669 const char *filename
;
673 unsigned int size
, max_size
;
676 TRACE("path %s\n", path
);
678 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
681 WARN("failed to get ref\n");
685 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
688 TRACE("no data fork, so trying resource fork\n");
689 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
692 TRACE("unable to open resource fork\n");
699 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
702 CloseResFile(res_ref
);
706 out_dir
= find_cache_dir();
708 filename
= strrchr(path
, '/');
709 if(!filename
) filename
= path
;
712 /* output filename has the form out_dir/filename_%04x.ttf */
713 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
720 unsigned short *num_faces_ptr
, num_faces
, face
;
723 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
725 fond
= Get1IndResource(fond_res
, idx
);
727 TRACE("got fond resource %d\n", idx
);
730 fam_rec
= *(FamRec
**)fond
;
731 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
732 num_faces
= GET_BE_WORD(*num_faces_ptr
);
734 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
735 TRACE("num faces %04x\n", num_faces
);
736 for(face
= 0; face
< num_faces
; face
++, assoc
++)
739 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
740 unsigned short size
, font_id
;
743 size
= GET_BE_WORD(assoc
->fontSize
);
744 font_id
= GET_BE_WORD(assoc
->fontID
);
747 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
751 TRACE("trying to load sfnt id %04x\n", font_id
);
752 sfnt
= GetResource(sfnt_res
, font_id
);
755 TRACE("can't get sfnt resource %04x\n", font_id
);
759 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
764 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
766 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
767 if(fd
!= -1 || errno
== EEXIST
)
771 unsigned char *sfnt_data
;
774 sfnt_data
= *(unsigned char**)sfnt
;
775 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
779 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
782 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
784 ret
.array
[ret
.size
++] = output
;
788 WARN("unable to create %s\n", output
);
789 HeapFree(GetProcessHeap(), 0, output
);
792 ReleaseResource(sfnt
);
795 ReleaseResource(fond
);
798 CloseResFile(res_ref
);
803 #endif /* HAVE_CARBON_CARBON_H */
805 static inline BOOL
is_win9x(void)
807 return GetVersion() & 0x80000000;
810 This function builds an FT_Fixed from a float. It puts the integer part
811 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
812 It fails if the integer part of the float number is greater than SHORT_MAX.
814 static inline FT_Fixed
FT_FixedFromFloat(float f
)
817 unsigned short fract
= (f
- value
) * 0xFFFF;
818 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
822 This function builds an FT_Fixed from a FIXED. It simply put f.value
823 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
825 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
827 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
831 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
836 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
837 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
839 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
840 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
842 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
844 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
846 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
850 file
= strrchr(face
->file
, '/');
855 if(!strcasecmp(file
, file_nameA
))
857 HeapFree(GetProcessHeap(), 0, file_nameA
);
862 HeapFree(GetProcessHeap(), 0, file_nameA
);
866 static Family
*find_family_from_name(const WCHAR
*name
)
870 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
872 if(!strcmpiW(family
->FamilyName
, name
))
879 static void DumpSubstList(void)
883 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
885 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
886 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
887 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
889 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
890 debugstr_w(psub
->to
.name
));
895 static LPWSTR
strdupW(LPCWSTR p
)
898 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
899 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
904 static LPSTR
strdupA(LPCSTR p
)
907 DWORD len
= (strlen(p
) + 1);
908 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
913 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
918 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
920 if(!strcmpiW(element
->from
.name
, from_name
) &&
921 (element
->from
.charset
== from_charset
||
922 element
->from
.charset
== -1))
929 #define ADD_FONT_SUBST_FORCE 1
931 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
933 FontSubst
*from_exist
, *to_exist
;
935 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
937 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
939 list_remove(&from_exist
->entry
);
940 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
941 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
942 HeapFree(GetProcessHeap(), 0, from_exist
);
948 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
952 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
953 subst
->to
.name
= strdupW(to_exist
->to
.name
);
956 list_add_tail(subst_list
, &subst
->entry
);
961 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
962 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
963 HeapFree(GetProcessHeap(), 0, subst
);
967 static void split_subst_info(NameCs
*nc
, LPSTR str
)
969 CHAR
*p
= strrchr(str
, ',');
974 nc
->charset
= strtol(p
+1, NULL
, 10);
977 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
978 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
979 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
982 static void LoadSubstList(void)
986 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
990 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
991 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
992 &hkey
) == ERROR_SUCCESS
) {
994 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
995 &valuelen
, &datalen
, NULL
, NULL
);
997 valuelen
++; /* returned value doesn't include room for '\0' */
998 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
999 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1003 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1004 &dlen
) == ERROR_SUCCESS
) {
1005 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1007 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1008 split_subst_info(&psub
->from
, value
);
1009 split_subst_info(&psub
->to
, data
);
1011 /* Win 2000 doesn't allow mapping between different charsets
1012 or mapping of DEFAULT_CHARSET */
1013 if((psub
->to
.charset
!= psub
->from
.charset
) ||
1014 psub
->to
.charset
== DEFAULT_CHARSET
) {
1015 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1016 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1017 HeapFree(GetProcessHeap(), 0, psub
);
1019 add_font_subst(&font_subst_list
, psub
, 0);
1021 /* reset dlen and vlen */
1025 HeapFree(GetProcessHeap(), 0, data
);
1026 HeapFree(GetProcessHeap(), 0, value
);
1031 static WCHAR
*get_familyname(FT_Face ft_face
)
1033 WCHAR
*family
= NULL
;
1035 FT_UInt num_names
, name_index
, i
;
1037 if(FT_IS_SFNT(ft_face
))
1039 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1041 for(name_index
= 0; name_index
< num_names
; name_index
++)
1043 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1045 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
1046 (name
.language_id
== GetUserDefaultLCID()) &&
1047 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
1048 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
1050 /* String is not nul terminated and string_len is a byte length. */
1051 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1052 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1054 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1055 family
[i
] = GET_BE_WORD(*tmp
);
1059 TRACE("Got localised name %s\n", debugstr_w(family
));
1070 /*****************************************************************
1073 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1074 * of FreeType that don't export this function.
1077 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1082 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1083 if(pFT_Load_Sfnt_Table
)
1085 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1087 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1088 else /* Do it the hard way */
1090 TT_Face tt_face
= (TT_Face
) ft_face
;
1091 SFNT_Interface
*sfnt
;
1092 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1095 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1099 /* A field was added in the middle of the structure in 2.1.x */
1100 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1102 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1110 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1111 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1112 "Please upgrade your freetype library.\n");
1115 err
= FT_Err_Unimplemented_Feature
;
1122 #define ADDFONT_EXTERNAL_FONT 0x01
1123 #define ADDFONT_FORCE_BITMAP 0x02
1124 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1128 TT_Header
*pHeader
= NULL
;
1129 WCHAR
*english_family
, *localised_family
, *StyleW
;
1133 struct list
*family_elem_ptr
, *face_elem_ptr
;
1135 FT_Long face_index
= 0, num_faces
;
1136 #ifdef HAVE_FREETYPE_FTWINFNT_H
1137 FT_WinFNT_HeaderRec winfnt_header
;
1139 int i
, bitmap_num
, internal_leading
;
1142 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1143 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1145 #ifdef HAVE_CARBON_CARBON_H
1146 if(file
&& !fake_family
)
1148 char **mac_list
= expand_mac_font(file
);
1151 BOOL had_one
= FALSE
;
1153 for(cursor
= mac_list
; *cursor
; cursor
++)
1156 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1157 HeapFree(GetProcessHeap(), 0, *cursor
);
1159 HeapFree(GetProcessHeap(), 0, mac_list
);
1164 #endif /* HAVE_CARBON_CARBON_H */
1167 char *family_name
= fake_family
;
1171 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1172 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1175 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1176 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1180 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1184 if(!FT_IS_SFNT(ft_face
) && (FT_IS_SCALABLE(ft_face
) || !(flags
& ADDFONT_FORCE_BITMAP
))) { /* for now we'll accept TT/OT or bitmap fonts*/
1185 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1186 pFT_Done_Face(ft_face
);
1190 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1191 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1192 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1193 pFT_Done_Face(ft_face
);
1197 if(FT_IS_SFNT(ft_face
))
1199 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1200 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1201 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1203 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1204 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1205 pFT_Done_Face(ft_face
);
1209 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1210 we don't want to load these. */
1211 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1215 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1217 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1218 pFT_Done_Face(ft_face
);
1224 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1225 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1226 pFT_Done_Face(ft_face
);
1232 localised_family
= get_familyname(ft_face
);
1233 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1235 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1236 HeapFree(GetProcessHeap(), 0, localised_family
);
1237 num_faces
= ft_face
->num_faces
;
1238 pFT_Done_Face(ft_face
);
1241 HeapFree(GetProcessHeap(), 0, localised_family
);
1245 family_name
= ft_face
->family_name
;
1249 My_FT_Bitmap_Size
*size
= NULL
;
1252 if(!FT_IS_SCALABLE(ft_face
))
1253 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1255 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1256 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1257 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1259 localised_family
= NULL
;
1261 localised_family
= get_familyname(ft_face
);
1262 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1263 HeapFree(GetProcessHeap(), 0, localised_family
);
1264 localised_family
= NULL
;
1269 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1270 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1271 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1276 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1277 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1278 list_init(&family
->faces
);
1279 list_add_tail(&font_list
, &family
->entry
);
1281 if(localised_family
) {
1282 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1283 subst
->from
.name
= strdupW(english_family
);
1284 subst
->from
.charset
= -1;
1285 subst
->to
.name
= strdupW(localised_family
);
1286 subst
->to
.charset
= -1;
1287 add_font_subst(&font_subst_list
, subst
, 0);
1290 HeapFree(GetProcessHeap(), 0, localised_family
);
1291 HeapFree(GetProcessHeap(), 0, english_family
);
1293 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1294 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1295 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1297 internal_leading
= 0;
1298 memset(&fs
, 0, sizeof(fs
));
1300 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1302 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1303 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1304 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1305 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1306 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1307 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1308 if(pOS2
->version
== 0) {
1311 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1312 fs
.fsCsb
[0] |= FS_LATIN1
;
1314 fs
.fsCsb
[0] |= FS_SYMBOL
;
1317 #ifdef HAVE_FREETYPE_FTWINFNT_H
1318 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1320 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1321 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1322 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1324 internal_leading
= winfnt_header
.internal_leading
;
1328 face_elem_ptr
= list_head(&family
->faces
);
1329 while(face_elem_ptr
) {
1330 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1331 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1332 if(!strcmpW(face
->StyleName
, StyleW
) &&
1333 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1334 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1335 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1336 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1339 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1340 HeapFree(GetProcessHeap(), 0, StyleW
);
1341 pFT_Done_Face(ft_face
);
1344 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1345 TRACE("Original font is newer so skipping this one\n");
1346 HeapFree(GetProcessHeap(), 0, StyleW
);
1347 pFT_Done_Face(ft_face
);
1350 TRACE("Replacing original with this one\n");
1351 list_remove(&face
->entry
);
1352 HeapFree(GetProcessHeap(), 0, face
->file
);
1353 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1354 HeapFree(GetProcessHeap(), 0, face
);
1359 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1360 face
->cached_enum_data
= NULL
;
1361 list_add_tail(&family
->faces
, &face
->entry
);
1362 face
->StyleName
= StyleW
;
1365 face
->file
= strdupA(file
);
1366 face
->font_data_ptr
= NULL
;
1367 face
->font_data_size
= 0;
1372 face
->font_data_ptr
= font_data_ptr
;
1373 face
->font_data_size
= font_data_size
;
1375 face
->face_index
= face_index
;
1376 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
1377 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
1378 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1379 face
->family
= family
;
1380 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1382 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1384 if(FT_IS_SCALABLE(ft_face
)) {
1385 memset(&face
->size
, 0, sizeof(face
->size
));
1386 face
->scalable
= TRUE
;
1388 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1389 size
->height
, size
->width
, size
->size
>> 6,
1390 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1391 face
->size
.height
= size
->height
;
1392 face
->size
.width
= size
->width
;
1393 face
->size
.size
= size
->size
;
1394 face
->size
.x_ppem
= size
->x_ppem
;
1395 face
->size
.y_ppem
= size
->y_ppem
;
1396 face
->size
.internal_leading
= internal_leading
;
1397 face
->scalable
= FALSE
;
1400 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1402 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1404 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1405 face
->ntmFlags
= NTM_PS_OPENTYPE
;
1410 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1411 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1412 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1413 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1416 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1417 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1418 switch(ft_face
->charmaps
[i
]->encoding
) {
1419 case FT_ENCODING_UNICODE
:
1420 case FT_ENCODING_APPLE_ROMAN
:
1421 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1423 case FT_ENCODING_MS_SYMBOL
:
1424 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1432 if (!(face
->fs
.fsCsb
[0] & FS_SYMBOL
))
1433 have_installed_roman_font
= TRUE
;
1434 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1436 num_faces
= ft_face
->num_faces
;
1437 pFT_Done_Face(ft_face
);
1438 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1439 debugstr_w(StyleW
));
1440 } while(num_faces
> ++face_index
);
1444 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1446 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1449 static void DumpFontList(void)
1453 struct list
*family_elem_ptr
, *face_elem_ptr
;
1455 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1456 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1457 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1458 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1459 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1460 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1462 TRACE(" %d", face
->size
.height
);
1469 /***********************************************************
1470 * The replacement list is a way to map an entire font
1471 * family onto another family. For example adding
1473 * [HKCU\Software\Wine\Fonts\Replacements]
1474 * "Wingdings"="Winedings"
1476 * would enumerate the Winedings font both as Winedings and
1477 * Wingdings. However if a real Wingdings font is present the
1478 * replacement does not take place.
1481 static void LoadReplaceList(void)
1484 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1489 struct list
*family_elem_ptr
, *face_elem_ptr
;
1492 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1493 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1495 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1496 &valuelen
, &datalen
, NULL
, NULL
);
1498 valuelen
++; /* returned value doesn't include room for '\0' */
1499 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1500 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1504 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1505 &dlen
) == ERROR_SUCCESS
) {
1506 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1507 /* "NewName"="Oldname" */
1508 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1510 /* Find the old family and hence all of the font files
1512 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1513 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1514 if(!strcmpiW(family
->FamilyName
, data
)) {
1515 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1516 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1517 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1518 debugstr_w(face
->StyleName
), familyA
);
1519 /* Now add a new entry with the new family name */
1520 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1525 /* reset dlen and vlen */
1529 HeapFree(GetProcessHeap(), 0, data
);
1530 HeapFree(GetProcessHeap(), 0, value
);
1535 /*************************************************************
1538 static BOOL
init_system_links(void)
1540 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1541 'W','i','n','d','o','w','s',' ','N','T','\\',
1542 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1543 'S','y','s','t','e','m','L','i','n','k',0};
1546 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1547 WCHAR
*value
, *data
;
1548 WCHAR
*entry
, *next
;
1549 SYSTEM_LINKS
*font_link
, *system_font_link
;
1550 CHILD_FONT
*child_font
;
1551 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1552 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1553 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1559 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1561 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1562 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1563 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1564 val_len
= max_val
+ 1;
1565 data_len
= max_data
;
1567 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1569 TRACE("%s:\n", debugstr_w(value
));
1571 memset(&fs
, 0, sizeof(fs
));
1572 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1573 psub
= get_font_subst(&font_subst_list
, value
, -1);
1574 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1575 list_init(&font_link
->links
);
1576 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1579 CHILD_FONT
*child_font
;
1581 TRACE("\t%s\n", debugstr_w(entry
));
1583 next
= entry
+ strlenW(entry
) + 1;
1585 face_name
= strchrW(entry
, ',');
1589 while(isspaceW(*face_name
))
1592 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1594 face_name
= psub
->to
.name
;
1596 face
= find_face_from_filename(entry
, face_name
);
1599 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1603 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1604 child_font
->face
= face
;
1605 child_font
->font
= NULL
;
1606 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1607 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1608 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1609 list_add_tail(&font_link
->links
, &child_font
->entry
);
1611 family
= find_family_from_name(font_link
->font_name
);
1614 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1616 face
->fs_links
= fs
;
1619 list_add_tail(&system_links
, &font_link
->entry
);
1620 val_len
= max_val
+ 1;
1621 data_len
= max_data
;
1624 HeapFree(GetProcessHeap(), 0, value
);
1625 HeapFree(GetProcessHeap(), 0, data
);
1629 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1632 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1633 system_font_link
->font_name
= strdupW(System
);
1634 list_init(&system_font_link
->links
);
1636 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1639 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1640 child_font
->face
= face
;
1641 child_font
->font
= NULL
;
1642 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1643 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1645 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1647 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1649 CHILD_FONT
*font_link_entry
;
1650 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1652 CHILD_FONT
*new_child
;
1653 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1654 new_child
->face
= font_link_entry
->face
;
1655 new_child
->font
= NULL
;
1656 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1661 list_add_tail(&system_links
, &system_font_link
->entry
);
1665 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1668 struct dirent
*dent
;
1669 char path
[MAX_PATH
];
1671 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1673 dir
= opendir(dirname
);
1675 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1678 while((dent
= readdir(dir
)) != NULL
) {
1679 struct stat statbuf
;
1681 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1684 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1686 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1688 if(stat(path
, &statbuf
) == -1)
1690 WARN("Can't stat %s\n", debugstr_a(path
));
1693 if(S_ISDIR(statbuf
.st_mode
))
1694 ReadFontDir(path
, external_fonts
);
1696 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1702 static void load_fontconfig_fonts(void)
1704 #ifdef SONAME_LIBFONTCONFIG
1705 void *fc_handle
= NULL
;
1714 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1716 TRACE("Wine cannot find the fontconfig library (%s).\n",
1717 SONAME_LIBFONTCONFIG
);
1720 #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;}
1721 LOAD_FUNCPTR(FcConfigGetCurrent
);
1722 LOAD_FUNCPTR(FcFontList
);
1723 LOAD_FUNCPTR(FcFontSetDestroy
);
1724 LOAD_FUNCPTR(FcInit
);
1725 LOAD_FUNCPTR(FcObjectSetAdd
);
1726 LOAD_FUNCPTR(FcObjectSetCreate
);
1727 LOAD_FUNCPTR(FcObjectSetDestroy
);
1728 LOAD_FUNCPTR(FcPatternCreate
);
1729 LOAD_FUNCPTR(FcPatternDestroy
);
1730 LOAD_FUNCPTR(FcPatternGetBool
);
1731 LOAD_FUNCPTR(FcPatternGetString
);
1734 if(!pFcInit()) return;
1736 config
= pFcConfigGetCurrent();
1737 pat
= pFcPatternCreate();
1738 os
= pFcObjectSetCreate();
1739 pFcObjectSetAdd(os
, FC_FILE
);
1740 pFcObjectSetAdd(os
, FC_SCALABLE
);
1741 fontset
= pFcFontList(config
, pat
, os
);
1742 if(!fontset
) return;
1743 for(i
= 0; i
< fontset
->nfont
; i
++) {
1746 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1748 TRACE("fontconfig: %s\n", file
);
1750 /* We're just interested in OT/TT fonts for now, so this hack just
1751 picks up the scalable fonts without extensions .pf[ab] to save time
1752 loading every other font */
1754 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1756 TRACE("not scalable\n");
1760 len
= strlen( file
);
1761 if(len
< 4) continue;
1762 ext
= &file
[ len
- 3 ];
1763 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1764 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1766 pFcFontSetDestroy(fontset
);
1767 pFcObjectSetDestroy(os
);
1768 pFcPatternDestroy(pat
);
1774 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1777 const char *data_dir
= wine_get_data_dir();
1779 if (!data_dir
) data_dir
= wine_get_build_dir();
1786 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1788 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1790 strcpy(unix_name
, data_dir
);
1791 strcat(unix_name
, "/fonts/");
1793 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1795 EnterCriticalSection( &freetype_cs
);
1796 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1797 LeaveCriticalSection( &freetype_cs
);
1798 HeapFree(GetProcessHeap(), 0, unix_name
);
1803 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1805 static const WCHAR slashW
[] = {'\\','\0'};
1807 WCHAR windowsdir
[MAX_PATH
];
1810 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1811 strcatW(windowsdir
, fontsW
);
1812 strcatW(windowsdir
, slashW
);
1813 strcatW(windowsdir
, file
);
1814 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1815 EnterCriticalSection( &freetype_cs
);
1816 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1817 LeaveCriticalSection( &freetype_cs
);
1818 HeapFree(GetProcessHeap(), 0, unixname
);
1823 static void load_system_fonts(void)
1826 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1827 const WCHAR
* const *value
;
1829 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1832 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1833 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1834 strcatW(windowsdir
, fontsW
);
1835 for(value
= SystemFontValues
; *value
; value
++) {
1836 dlen
= sizeof(data
);
1837 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1841 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1842 if((unixname
= wine_get_unix_file_name(pathW
))) {
1843 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1844 HeapFree(GetProcessHeap(), 0, unixname
);
1847 load_font_from_data_dir(data
);
1854 /*************************************************************
1856 * This adds registry entries for any externally loaded fonts
1857 * (fonts from fontconfig or FontDirs). It also deletes entries
1858 * of no longer existing fonts.
1861 static void update_reg_entries(void)
1863 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1868 struct list
*family_elem_ptr
, *face_elem_ptr
;
1870 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1871 static const WCHAR spaceW
[] = {' ', '\0'};
1874 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1875 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1876 ERR("Can't create Windows font reg key\n");
1880 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1881 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1882 ERR("Can't create Windows font reg key\n");
1886 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1887 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
1888 ERR("Can't create external font reg key\n");
1892 /* enumerate the fonts and add external ones to the two keys */
1894 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1895 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1896 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1897 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1898 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1899 if(!face
->external
) continue;
1901 if(strcmpiW(face
->StyleName
, RegularW
))
1902 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1903 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1904 strcpyW(valueW
, family
->FamilyName
);
1905 if(len
!= len_fam
) {
1906 strcatW(valueW
, spaceW
);
1907 strcatW(valueW
, face
->StyleName
);
1909 strcatW(valueW
, TrueType
);
1911 file
= wine_get_dos_file_name(face
->file
);
1913 len
= strlenW(file
) + 1;
1916 if((path
= strrchr(face
->file
, '/')) == NULL
)
1920 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1922 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1923 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1925 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1926 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1927 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1929 HeapFree(GetProcessHeap(), 0, file
);
1930 HeapFree(GetProcessHeap(), 0, valueW
);
1934 if(external_key
) RegCloseKey(external_key
);
1935 if(win9x_key
) RegCloseKey(win9x_key
);
1936 if(winnt_key
) RegCloseKey(winnt_key
);
1940 static void delete_external_font_keys(void)
1942 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1943 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
1947 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1948 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1949 ERR("Can't create Windows font reg key\n");
1953 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1954 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1955 ERR("Can't create Windows font reg key\n");
1959 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
1960 ERR("Can't create external font reg key\n");
1964 /* Delete all external fonts added last time */
1966 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1967 &valuelen
, &datalen
, NULL
, NULL
);
1968 valuelen
++; /* returned value doesn't include room for '\0' */
1969 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1970 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1972 dlen
= datalen
* sizeof(WCHAR
);
1975 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1976 &dlen
) == ERROR_SUCCESS
) {
1978 RegDeleteValueW(winnt_key
, valueW
);
1979 RegDeleteValueW(win9x_key
, valueW
);
1980 /* reset dlen and vlen */
1984 HeapFree(GetProcessHeap(), 0, data
);
1985 HeapFree(GetProcessHeap(), 0, valueW
);
1987 /* Delete the old external fonts key */
1988 RegCloseKey(external_key
);
1989 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1992 if(win9x_key
) RegCloseKey(win9x_key
);
1993 if(winnt_key
) RegCloseKey(winnt_key
);
1996 /*************************************************************
1997 * WineEngAddFontResourceEx
2000 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2003 if (ft_handle
) /* do it only if we have freetype up and running */
2008 FIXME("Ignoring flags %x\n", flags
);
2010 if((unixname
= wine_get_unix_file_name(file
)))
2012 EnterCriticalSection( &freetype_cs
);
2013 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2014 LeaveCriticalSection( &freetype_cs
);
2015 HeapFree(GetProcessHeap(), 0, unixname
);
2017 if (!ret
&& !strchrW(file
, '\\')) {
2018 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2019 ret
= load_font_from_winfonts_dir(file
);
2021 /* Try in datadir/fonts (or builddir/fonts),
2022 * needed for Magic the Gathering Online
2024 ret
= load_font_from_data_dir(file
);
2031 /*************************************************************
2032 * WineEngAddFontMemResourceEx
2035 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2037 if (ft_handle
) /* do it only if we have freetype up and running */
2039 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2041 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2042 memcpy(pFontCopy
, pbFont
, cbFont
);
2044 EnterCriticalSection( &freetype_cs
);
2045 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2046 LeaveCriticalSection( &freetype_cs
);
2050 TRACE("AddFontToList failed\n");
2051 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2054 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2055 * For now return something unique but quite random
2057 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2058 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2065 /*************************************************************
2066 * WineEngRemoveFontResourceEx
2069 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2075 static const struct nls_update_font_list
2077 UINT ansi_cp
, oem_cp
;
2078 const char *oem
, *fixed
, *system
;
2079 const char *courier
, *serif
, *small
, *sserif
;
2080 /* these are for font substitute */
2081 const char *shelldlg
, *tmsrmn
;
2082 } nls_update_font_list
[] =
2084 /* Latin 1 (United States) */
2085 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2086 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2087 "Tahoma","Times New Roman",
2089 /* Latin 1 (Multilingual) */
2090 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2091 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2092 "Tahoma","Times New Roman", /* FIXME unverified */
2094 /* Eastern Europe */
2095 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2096 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2097 "Tahoma","Times New Roman", /* FIXME unverified */
2100 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2101 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2102 "Tahoma","Times New Roman", /* FIXME unverified */
2105 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2106 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2107 "Tahoma","Times New Roman", /* FIXME unverified */
2110 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2111 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2112 "Tahoma","Times New Roman", /* FIXME unverified */
2115 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2116 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2117 "Tahoma","Times New Roman", /* FIXME unverified */
2120 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2121 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2122 "Tahoma","Times New Roman", /* FIXME unverified */
2125 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2126 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2127 "Tahoma","Times New Roman", /* FIXME unverified */
2130 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2131 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2132 "Tahoma","Times New Roman", /* FIXME unverified */
2135 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2136 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2137 "Tahoma","Times New Roman", /* FIXME unverified */
2140 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2141 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2142 "MS UI Gothic","MS Serif",
2144 /* Chinese Simplified */
2145 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2146 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2147 "Tahoma", "Times New Roman", /* FIXME unverified */
2150 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2151 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2154 /* Chinese Traditional */
2155 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2156 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2157 "PMingLiU", "MingLiU",
2161 static inline HKEY
create_fonts_NT_registry_key(void)
2165 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2166 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2170 static inline HKEY
create_fonts_9x_registry_key(void)
2174 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2175 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2179 static inline HKEY
create_config_fonts_registry_key(void)
2183 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2184 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2188 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2190 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2191 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2192 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2193 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2196 static void update_font_info(void)
2198 char buf
[40], cpbuf
[40];
2201 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2203 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2206 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2207 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2208 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2209 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2210 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2212 /* Setup DefaultFallback usage */
2214 use_default_fallback
= TRUE
;
2217 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2219 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2224 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2226 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2228 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2231 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2233 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2234 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2238 hkey
= create_config_fonts_registry_key();
2239 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2240 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2241 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2244 hkey
= create_fonts_NT_registry_key();
2245 add_font_list(hkey
, &nls_update_font_list
[i
]);
2248 hkey
= create_fonts_9x_registry_key();
2249 add_font_list(hkey
, &nls_update_font_list
[i
]);
2252 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2254 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2255 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2256 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2257 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2263 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2267 static BOOL
init_freetype(void)
2269 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2272 "Wine cannot find the FreeType font library. To enable Wine to\n"
2273 "use TrueType fonts please install a version of FreeType greater than\n"
2274 "or equal to 2.0.5.\n"
2275 "http://www.freetype.org\n");
2279 #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;}
2281 LOAD_FUNCPTR(FT_Vector_Unit
)
2282 LOAD_FUNCPTR(FT_Done_Face
)
2283 LOAD_FUNCPTR(FT_Get_Char_Index
)
2284 LOAD_FUNCPTR(FT_Get_Module
)
2285 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2286 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2287 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2288 LOAD_FUNCPTR(FT_Init_FreeType
)
2289 LOAD_FUNCPTR(FT_Load_Glyph
)
2290 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2291 LOAD_FUNCPTR(FT_MulFix
)
2292 LOAD_FUNCPTR(FT_New_Face
)
2293 LOAD_FUNCPTR(FT_New_Memory_Face
)
2294 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2295 LOAD_FUNCPTR(FT_Outline_Transform
)
2296 LOAD_FUNCPTR(FT_Outline_Translate
)
2297 LOAD_FUNCPTR(FT_Select_Charmap
)
2298 LOAD_FUNCPTR(FT_Set_Charmap
)
2299 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2300 LOAD_FUNCPTR(FT_Vector_Transform
)
2303 /* Don't warn if these ones are missing */
2304 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2305 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2306 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2307 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2308 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2309 #ifdef HAVE_FREETYPE_FTWINFNT_H
2310 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2312 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2313 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2314 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2315 <= 2.0.3 has FT_Sqrt64 */
2319 if(pFT_Init_FreeType(&library
) != 0) {
2320 ERR("Can't init FreeType library\n");
2321 wine_dlclose(ft_handle
, NULL
, 0);
2325 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2326 if (pFT_Library_Version
)
2327 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2329 if (FT_Version
.major
<=0)
2335 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2336 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2337 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2338 ((FT_Version
.patch
) & 0x0000ff);
2344 "Wine cannot find certain functions that it needs inside the FreeType\n"
2345 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2346 "FreeType to at least version 2.0.5.\n"
2347 "http://www.freetype.org\n");
2348 wine_dlclose(ft_handle
, NULL
, 0);
2353 /*************************************************************
2356 * Initialize FreeType library and create a list of available faces
2358 BOOL
WineEngInit(void)
2360 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2361 static const WCHAR pathW
[] = {'P','a','t','h',0};
2363 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2365 WCHAR windowsdir
[MAX_PATH
];
2368 const char *data_dir
;
2372 /* update locale dependent font info in registry */
2375 if(!init_freetype()) return FALSE
;
2377 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2378 ERR("Failed to create font mutex\n");
2381 WaitForSingleObject(font_mutex
, INFINITE
);
2383 delete_external_font_keys();
2385 /* load the system bitmap fonts */
2386 load_system_fonts();
2388 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2389 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2390 strcatW(windowsdir
, fontsW
);
2391 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2393 ReadFontDir(unixname
, FALSE
);
2394 HeapFree(GetProcessHeap(), 0, unixname
);
2397 /* load the system truetype fonts */
2398 data_dir
= wine_get_data_dir();
2399 if (!data_dir
) data_dir
= wine_get_build_dir();
2400 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2401 strcpy(unixname
, data_dir
);
2402 strcat(unixname
, "/fonts/");
2403 ReadFontDir(unixname
, TRUE
);
2404 HeapFree(GetProcessHeap(), 0, unixname
);
2407 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2408 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2409 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2411 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2412 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2413 &hkey
) == ERROR_SUCCESS
) {
2415 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2416 &valuelen
, &datalen
, NULL
, NULL
);
2418 valuelen
++; /* returned value doesn't include room for '\0' */
2419 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2420 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2423 dlen
= datalen
* sizeof(WCHAR
);
2425 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2426 &dlen
) == ERROR_SUCCESS
) {
2427 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2429 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2431 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2432 HeapFree(GetProcessHeap(), 0, unixname
);
2435 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2437 WCHAR pathW
[MAX_PATH
];
2438 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2441 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2442 if((unixname
= wine_get_unix_file_name(pathW
)))
2444 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2445 HeapFree(GetProcessHeap(), 0, unixname
);
2448 load_font_from_data_dir(data
);
2450 /* reset dlen and vlen */
2455 HeapFree(GetProcessHeap(), 0, data
);
2456 HeapFree(GetProcessHeap(), 0, valueW
);
2460 load_fontconfig_fonts();
2462 /* then look in any directories that we've specified in the config file */
2463 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2464 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2470 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2472 len
+= sizeof(WCHAR
);
2473 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2474 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2476 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2477 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2478 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2479 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2483 LPSTR next
= strchr( ptr
, ':' );
2484 if (next
) *next
++ = 0;
2485 ReadFontDir( ptr
, TRUE
);
2488 HeapFree( GetProcessHeap(), 0, valueA
);
2490 HeapFree( GetProcessHeap(), 0, valueW
);
2499 update_reg_entries();
2501 init_system_links();
2503 ReleaseMutex(font_mutex
);
2508 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2511 TT_HoriHeader
*pHori
;
2515 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2516 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2518 if(height
== 0) height
= 16;
2520 /* Calc. height of EM square:
2522 * For +ve lfHeight we have
2523 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2524 * Re-arranging gives:
2525 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2527 * For -ve lfHeight we have
2529 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2530 * with il = winAscent + winDescent - units_per_em]
2535 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2536 ppem
= ft_face
->units_per_EM
* height
/
2537 (pHori
->Ascender
- pHori
->Descender
);
2539 ppem
= ft_face
->units_per_EM
* height
/
2540 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2548 static struct font_mapping
*map_font_file( const char *name
)
2550 struct font_mapping
*mapping
;
2554 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2555 if (fstat( fd
, &st
) == -1) goto error
;
2557 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2559 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2561 mapping
->refcount
++;
2566 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2569 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2572 if (mapping
->data
== MAP_FAILED
)
2574 HeapFree( GetProcessHeap(), 0, mapping
);
2577 mapping
->refcount
= 1;
2578 mapping
->dev
= st
.st_dev
;
2579 mapping
->ino
= st
.st_ino
;
2580 mapping
->size
= st
.st_size
;
2581 list_add_tail( &mappings_list
, &mapping
->entry
);
2589 static void unmap_font_file( struct font_mapping
*mapping
)
2591 if (!--mapping
->refcount
)
2593 list_remove( &mapping
->entry
);
2594 munmap( mapping
->data
, mapping
->size
);
2595 HeapFree( GetProcessHeap(), 0, mapping
);
2599 static LONG
load_VDMX(GdiFont
*, LONG
);
2601 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2608 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2612 if (!(font
->mapping
= map_font_file( face
->file
)))
2614 WARN("failed to map %s\n", debugstr_a(face
->file
));
2617 data_ptr
= font
->mapping
->data
;
2618 data_size
= font
->mapping
->size
;
2622 data_ptr
= face
->font_data_ptr
;
2623 data_size
= face
->font_data_size
;
2626 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2628 ERR("FT_New_Face rets %d\n", err
);
2632 /* set it here, as load_VDMX needs it */
2633 font
->ft_face
= ft_face
;
2635 if(FT_IS_SCALABLE(ft_face
)) {
2636 /* load the VDMX table if we have one */
2637 font
->ppem
= load_VDMX(font
, height
);
2639 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2641 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2642 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2644 font
->ppem
= height
;
2645 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2646 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2652 static int get_nearest_charset(Face
*face
, int *cp
)
2654 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2655 a single face with the requested charset. The idea is to check if
2656 the selected font supports the current ANSI codepage, if it does
2657 return the corresponding charset, else return the first charset */
2660 int acp
= GetACP(), i
;
2664 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2665 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2666 return csi
.ciCharset
;
2668 for(i
= 0; i
< 32; i
++) {
2670 if(face
->fs
.fsCsb
[0] & fs0
) {
2671 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2673 return csi
.ciCharset
;
2676 FIXME("TCI failing on %x\n", fs0
);
2680 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2681 face
->fs
.fsCsb
[0], face
->file
);
2683 return DEFAULT_CHARSET
;
2686 static GdiFont
*alloc_font(void)
2688 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2690 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2691 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2693 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2694 ret
->total_kern_pairs
= (DWORD
)-1;
2695 ret
->kern_pairs
= NULL
;
2696 list_init(&ret
->hfontlist
);
2697 list_init(&ret
->child_fonts
);
2701 static void free_font(GdiFont
*font
)
2703 struct list
*cursor
, *cursor2
;
2706 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2708 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2709 struct list
*first_hfont
;
2710 HFONTLIST
*hfontlist
;
2711 list_remove(cursor
);
2714 first_hfont
= list_head(&child
->font
->hfontlist
);
2715 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2716 DeleteObject(hfontlist
->hfont
);
2717 HeapFree(GetProcessHeap(), 0, hfontlist
);
2718 free_font(child
->font
);
2720 HeapFree(GetProcessHeap(), 0, child
);
2723 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2724 if (font
->mapping
) unmap_font_file( font
->mapping
);
2725 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2726 HeapFree(GetProcessHeap(), 0, font
->potm
);
2727 HeapFree(GetProcessHeap(), 0, font
->name
);
2728 for (i
= 0; i
< font
->gmsize
; i
++)
2729 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2730 HeapFree(GetProcessHeap(), 0, font
->gm
);
2731 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
2732 HeapFree(GetProcessHeap(), 0, font
);
2736 /*************************************************************
2739 * load the vdmx entry for the specified height
2742 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2743 ( ( (FT_ULong)_x4 << 24 ) | \
2744 ( (FT_ULong)_x3 << 16 ) | \
2745 ( (FT_ULong)_x2 << 8 ) | \
2748 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2763 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2767 BYTE devXRatio
, devYRatio
;
2768 USHORT numRecs
, numRatios
;
2769 DWORD result
, offset
= -1;
2773 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2775 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2778 /* FIXME: need the real device aspect ratio */
2782 numRecs
= GET_BE_WORD(hdr
[1]);
2783 numRatios
= GET_BE_WORD(hdr
[2]);
2785 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2786 for(i
= 0; i
< numRatios
; i
++) {
2789 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2790 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2793 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2795 if((ratio
.xRatio
== 0 &&
2796 ratio
.yStartRatio
== 0 &&
2797 ratio
.yEndRatio
== 0) ||
2798 (devXRatio
== ratio
.xRatio
&&
2799 devYRatio
>= ratio
.yStartRatio
&&
2800 devYRatio
<= ratio
.yEndRatio
))
2802 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2803 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2804 offset
= GET_BE_WORD(tmp
);
2810 FIXME("No suitable ratio found\n");
2814 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2816 BYTE startsz
, endsz
;
2819 recs
= GET_BE_WORD(group
.recs
);
2820 startsz
= group
.startsz
;
2821 endsz
= group
.endsz
;
2823 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2825 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2826 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2827 if(result
== GDI_ERROR
) {
2828 FIXME("Failed to retrieve vTable\n");
2833 for(i
= 0; i
< recs
; i
++) {
2834 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2835 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2836 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2838 if(yMax
+ -yMin
== height
) {
2841 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2844 if(yMax
+ -yMin
> height
) {
2847 goto end
; /* failed */
2849 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2850 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2851 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2852 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2858 TRACE("ppem not found for height %d\n", height
);
2862 if(ppem
< startsz
|| ppem
> endsz
)
2865 for(i
= 0; i
< recs
; i
++) {
2867 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2869 if(yPelHeight
> ppem
)
2872 if(yPelHeight
== ppem
) {
2873 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2874 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2875 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2881 HeapFree(GetProcessHeap(), 0, vTable
);
2887 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
2889 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2890 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2891 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2892 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2893 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2896 static void calc_hash(FONT_DESC
*pfd
)
2898 DWORD hash
= 0, *ptr
, two_chars
;
2902 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2904 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2906 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2908 pwc
= (WCHAR
*)&two_chars
;
2910 *pwc
= toupperW(*pwc
);
2912 *pwc
= toupperW(*pwc
);
2916 hash
^= !pfd
->can_use_bitmap
;
2921 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2926 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2929 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2930 fd
.can_use_bitmap
= can_use_bitmap
;
2933 /* try the in-use list */
2934 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2935 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2936 if(!fontcmp(ret
, &fd
)) {
2937 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2938 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2939 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2940 if(hflist
->hfont
== hfont
)
2943 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2944 hflist
->hfont
= hfont
;
2945 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2950 /* then the unused list */
2951 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2952 while(font_elem_ptr
) {
2953 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2954 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2955 if(!fontcmp(ret
, &fd
)) {
2956 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2957 assert(list_empty(&ret
->hfontlist
));
2958 TRACE("Found %p in unused list\n", ret
);
2959 list_remove(&ret
->entry
);
2960 list_add_head(&gdi_font_list
, &ret
->entry
);
2961 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2962 hflist
->hfont
= hfont
;
2963 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2971 /*************************************************************
2972 * create_child_font_list
2974 static BOOL
create_child_font_list(GdiFont
*font
)
2977 SYSTEM_LINKS
*font_link
;
2978 CHILD_FONT
*font_link_entry
, *new_child
;
2980 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2982 if(!strcmpW(font_link
->font_name
, font
->name
))
2984 TRACE("found entry in system list\n");
2985 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2987 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2988 new_child
->face
= font_link_entry
->face
;
2989 new_child
->font
= NULL
;
2990 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2991 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
2998 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2999 * Sans Serif. This is how asian windows get default fallbacks for fonts
3001 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3002 font
->charset
!= OEM_CHARSET
&&
3003 strcmpW(font
->name
,szDefaultFallbackLink
) != 0)
3004 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3006 if(!strcmpW(font_link
->font_name
,szDefaultFallbackLink
))
3008 TRACE("found entry in default fallback list\n");
3009 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3011 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3012 new_child
->face
= font_link_entry
->face
;
3013 new_child
->font
= NULL
;
3014 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3015 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3025 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3027 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3029 if (pFT_Set_Charmap
)
3032 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3034 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3036 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3038 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3040 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3041 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3043 switch (ft_face
->charmaps
[i
]->platform_id
)
3046 cmap_def
= ft_face
->charmaps
[i
];
3048 case 0: /* Apple Unicode */
3049 cmap0
= ft_face
->charmaps
[i
];
3051 case 1: /* Macintosh */
3052 cmap1
= ft_face
->charmaps
[i
];
3055 cmap2
= ft_face
->charmaps
[i
];
3057 case 3: /* Microsoft */
3058 cmap3
= ft_face
->charmaps
[i
];
3063 if (cmap3
) /* prefer Microsoft cmap table */
3064 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3066 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3068 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3070 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3072 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3074 return ft_err
== FT_Err_Ok
;
3077 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3080 /*************************************************************
3081 * WineEngCreateFontInstance
3084 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3087 Face
*face
, *best
, *best_bitmap
;
3088 Family
*family
, *last_resort_family
;
3089 struct list
*family_elem_ptr
, *face_elem_ptr
;
3090 INT height
, width
= 0;
3091 unsigned int score
= 0, new_score
;
3092 signed int diff
= 0, newdiff
;
3093 BOOL bd
, it
, can_use_bitmap
;
3098 EnterCriticalSection( &freetype_cs
);
3100 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
3102 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
3103 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3104 if(hflist
->hfont
== hfont
)
3106 LeaveCriticalSection( &freetype_cs
);
3111 if (!GetObjectW( hfont
, sizeof(lf
), &lf
))
3113 LeaveCriticalSection( &freetype_cs
);
3116 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3118 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3119 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3120 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3123 /* check the cache first */
3124 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
3125 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3126 LeaveCriticalSection( &freetype_cs
);
3130 TRACE("not in cache\n");
3131 if(list_empty(&font_list
)) /* No fonts installed */
3133 TRACE("No fonts installed\n");
3134 LeaveCriticalSection( &freetype_cs
);
3137 if(!have_installed_roman_font
)
3139 TRACE("No roman font installed\n");
3140 LeaveCriticalSection( &freetype_cs
);
3146 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3147 ret
->font_desc
.lf
= lf
;
3148 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3149 calc_hash(&ret
->font_desc
);
3150 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3151 hflist
->hfont
= hfont
;
3152 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3155 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3156 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3157 original value lfCharSet. Note this is a special case for
3158 Symbol and doesn't happen at least for "Wingdings*" */
3160 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3161 lf
.lfCharSet
= SYMBOL_CHARSET
;
3163 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3164 switch(lf
.lfCharSet
) {
3165 case DEFAULT_CHARSET
:
3166 csi
.fs
.fsCsb
[0] = 0;
3169 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3170 csi
.fs
.fsCsb
[0] = 0;
3176 if(lf
.lfFaceName
[0] != '\0') {
3178 SYSTEM_LINKS
*font_link
;
3179 CHILD_FONT
*font_link_entry
;
3180 LPWSTR FaceName
= lf
.lfFaceName
;
3183 * Check for a leading '@' this signals that the font is being
3184 * requested in tategaki mode (vertical writing subtitution) but
3185 * does not affect the fontface that is to be selected.
3187 if (lf
.lfFaceName
[0]=='@')
3188 FaceName
= &lf
.lfFaceName
[1];
3190 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3193 TRACE("substituting %s -> %s\n", debugstr_w(FaceName
),
3194 debugstr_w(psub
->to
.name
));
3195 strcpyW(FaceName
, psub
->to
.name
);
3198 /* We want a match on name and charset or just name if
3199 charset was DEFAULT_CHARSET. If the latter then
3200 we fixup the returned charset later in get_nearest_charset
3201 where we'll either use the charset of the current ansi codepage
3202 or if that's unavailable the first charset that the font supports.
3204 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3205 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3206 if(!strcmpiW(family
->FamilyName
, FaceName
)) {
3207 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3208 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3209 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3210 if(face
->scalable
|| can_use_bitmap
)
3217 * Try check the SystemLink list first for a replacement font.
3218 * We may find good replacements there.
3220 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3222 if(!strcmpiW(font_link
->font_name
, FaceName
))
3224 TRACE("found entry in system list\n");
3225 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3227 face
= font_link_entry
->face
;
3228 family
= face
->family
;
3229 if(csi
.fs
.fsCsb
[0] &
3230 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3232 if(face
->scalable
|| can_use_bitmap
)
3240 /* If requested charset was DEFAULT_CHARSET then try using charset
3241 corresponding to the current ansi codepage */
3242 if(!csi
.fs
.fsCsb
[0]) {
3244 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3245 FIXME("TCI failed on codepage %d\n", acp
);
3246 csi
.fs
.fsCsb
[0] = 0;
3248 lf
.lfCharSet
= csi
.ciCharset
;
3251 /* Face families are in the top 4 bits of lfPitchAndFamily,
3252 so mask with 0xF0 before testing */
3254 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3255 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3256 strcpyW(lf
.lfFaceName
, defFixed
);
3257 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3258 strcpyW(lf
.lfFaceName
, defSerif
);
3259 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3260 strcpyW(lf
.lfFaceName
, defSans
);
3262 strcpyW(lf
.lfFaceName
, defSans
);
3263 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3264 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3265 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3266 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3267 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3268 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3269 if(face
->scalable
|| can_use_bitmap
)
3275 last_resort_family
= NULL
;
3276 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3277 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3278 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3279 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3280 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3283 if(can_use_bitmap
&& !last_resort_family
)
3284 last_resort_family
= family
;
3289 if(last_resort_family
) {
3290 family
= last_resort_family
;
3291 csi
.fs
.fsCsb
[0] = 0;
3295 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3296 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3297 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3298 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3299 if(face
->scalable
) {
3300 csi
.fs
.fsCsb
[0] = 0;
3301 WARN("just using first face for now\n");
3304 if(can_use_bitmap
&& !last_resort_family
)
3305 last_resort_family
= family
;
3308 if(!last_resort_family
) {
3309 FIXME("can't find a single appropriate font - bailing\n");
3311 LeaveCriticalSection( &freetype_cs
);
3315 WARN("could only find a bitmap font - this will probably look awful!\n");
3316 family
= last_resort_family
;
3317 csi
.fs
.fsCsb
[0] = 0;
3320 it
= lf
.lfItalic
? 1 : 0;
3321 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3323 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
3324 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
3326 face
= best
= best_bitmap
= NULL
;
3327 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3329 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3331 new_score
= (face
->Italic
^ it
) + (face
->Bold
^ bd
);
3332 if(!best
|| new_score
<= score
)
3334 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3335 face
->Italic
, face
->Bold
, it
, bd
);
3338 if(best
->scalable
&& score
== 0) break;
3342 newdiff
= height
- (signed int)(best
->size
.height
);
3344 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3345 if(!best_bitmap
|| new_score
< score
||
3346 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3348 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3351 if(score
== 0 && diff
== 0) break;
3358 face
= best
->scalable
? best
: best_bitmap
;
3359 ret
->fake_italic
= (it
&& !face
->Italic
);
3360 ret
->fake_bold
= (bd
&& !face
->Bold
);
3364 if(csi
.fs
.fsCsb
[0]) {
3365 ret
->charset
= lf
.lfCharSet
;
3366 ret
->codepage
= csi
.ciACP
;
3369 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3371 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3372 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3374 ret
->aveWidth
= abs(lf
.lfWidth
);
3376 if(!face
->scalable
) {
3377 /* Windows uses integer scaling factors for bitmap fonts */
3378 INT scale
, scaled_height
;
3380 if (height
!= 0) height
= diff
;
3382 height
+= face
->size
.height
;
3384 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3385 scaled_height
= scale
* face
->size
.height
;
3386 /* XP allows not more than 10% deviation */
3387 if (scale
> 1 && scaled_height
- height
> scaled_height
/ 10) scale
--;
3388 ret
->scale_y
= scale
;
3390 width
= face
->size
.x_ppem
>> 6;
3391 height
= face
->size
.y_ppem
>> 6;
3395 TRACE("font scale y: %f\n", ret
->scale_y
);
3397 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3402 LeaveCriticalSection( &freetype_cs
);
3406 ret
->ntmFlags
= face
->ntmFlags
;
3408 if (ret
->charset
== SYMBOL_CHARSET
&&
3409 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3412 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3416 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3419 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3420 ret
->name
= strdupW(family
->FamilyName
);
3421 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3422 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3423 create_child_font_list(ret
);
3425 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3427 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3428 if (length
!= GDI_ERROR
)
3430 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3431 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3432 TRACE("Loaded GSUB table of %i bytes\n",length
);
3436 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3438 list_add_head(&gdi_font_list
, &ret
->entry
);
3439 LeaveCriticalSection( &freetype_cs
);
3443 static void dump_gdi_font_list(void)
3446 struct list
*elem_ptr
;
3448 TRACE("---------- gdiFont Cache ----------\n");
3449 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3450 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3451 TRACE("gdiFont=%p %s %d\n",
3452 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3455 TRACE("---------- Unused gdiFont Cache ----------\n");
3456 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3457 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3458 TRACE("gdiFont=%p %s %d\n",
3459 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3463 /*************************************************************
3464 * WineEngDestroyFontInstance
3466 * free the gdiFont associated with this handle
3469 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3474 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3477 EnterCriticalSection( &freetype_cs
);
3479 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3481 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3482 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3483 if(hflist
->hfont
== handle
)
3485 TRACE("removing child font %p from child list\n", gdiFont
);
3486 list_remove(&gdiFont
->entry
);
3487 LeaveCriticalSection( &freetype_cs
);
3492 TRACE("destroying hfont=%p\n", handle
);
3494 dump_gdi_font_list();
3496 font_elem_ptr
= list_head(&gdi_font_list
);
3497 while(font_elem_ptr
) {
3498 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3499 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3501 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3502 while(hfontlist_elem_ptr
) {
3503 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3504 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3505 if(hflist
->hfont
== handle
) {
3506 list_remove(&hflist
->entry
);
3507 HeapFree(GetProcessHeap(), 0, hflist
);
3511 if(list_empty(&gdiFont
->hfontlist
)) {
3512 TRACE("Moving to Unused list\n");
3513 list_remove(&gdiFont
->entry
);
3514 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3519 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3520 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3521 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3522 while(font_elem_ptr
) {
3523 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3524 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3525 TRACE("freeing %p\n", gdiFont
);
3526 list_remove(&gdiFont
->entry
);
3529 LeaveCriticalSection( &freetype_cs
);
3533 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3534 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3539 if (face
->cached_enum_data
)
3542 *pelf
= face
->cached_enum_data
->elf
;
3543 *pntm
= face
->cached_enum_data
->ntm
;
3544 *ptype
= face
->cached_enum_data
->type
;
3548 font
= alloc_font();
3550 if(face
->scalable
) {
3554 height
= face
->size
.y_ppem
>> 6;
3555 width
= face
->size
.x_ppem
>> 6;
3557 font
->scale_y
= 1.0;
3559 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3565 font
->name
= strdupW(face
->family
->FamilyName
);
3566 font
->ntmFlags
= face
->ntmFlags
;
3568 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3570 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3572 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3574 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3575 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3577 lstrcpynW(pelf
->elfFullName
,
3578 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
3580 lstrcpynW(pelf
->elfStyle
,
3581 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
3586 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
3588 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3590 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3591 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
3592 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
3595 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
3596 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3597 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3598 pntm
->ntmFontSig
= face
->fs
;
3600 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3602 pelf
->elfLogFont
.lfEscapement
= 0;
3603 pelf
->elfLogFont
.lfOrientation
= 0;
3604 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
3605 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3606 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
3607 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
3608 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
3609 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
3610 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
3611 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3612 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3613 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3614 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3617 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
3618 *ptype
|= TRUETYPE_FONTTYPE
;
3619 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
3620 *ptype
|= DEVICE_FONTTYPE
;
3621 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
3622 *ptype
|= RASTER_FONTTYPE
;
3624 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
3625 if (face
->cached_enum_data
)
3627 face
->cached_enum_data
->elf
= *pelf
;
3628 face
->cached_enum_data
->ntm
= *pntm
;
3629 face
->cached_enum_data
->type
= *ptype
;
3635 /*************************************************************
3639 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3643 struct list
*family_elem_ptr
, *face_elem_ptr
;
3645 NEWTEXTMETRICEXW ntm
;
3654 lf
.lfCharSet
= DEFAULT_CHARSET
;
3655 lf
.lfPitchAndFamily
= 0;
3656 lf
.lfFaceName
[0] = 0;
3660 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3662 EnterCriticalSection( &freetype_cs
);
3663 if(plf
->lfFaceName
[0]) {
3665 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3668 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3669 debugstr_w(psub
->to
.name
));
3671 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3675 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3676 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3677 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3678 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3679 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3680 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3681 for(i
= 0; i
< 32; i
++) {
3682 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3683 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3684 strcpyW(elf
.elfScript
, OEM_DOSW
);
3685 i
= 32; /* break out of loop */
3686 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3689 fs
.fsCsb
[0] = 1L << i
;
3691 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3693 csi
.ciCharset
= DEFAULT_CHARSET
;
3694 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3695 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3696 elf
.elfLogFont
.lfCharSet
=
3697 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3699 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3701 FIXME("Unknown elfscript for bit %d\n", i
);
3704 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3705 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3706 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3707 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3708 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3709 ntm
.ntmTm
.ntmFlags
);
3710 /* release section before callback (FIXME) */
3711 LeaveCriticalSection( &freetype_cs
);
3712 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3713 EnterCriticalSection( &freetype_cs
);
3719 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3720 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3721 face_elem_ptr
= list_head(&family
->faces
);
3722 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3723 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3724 for(i
= 0; i
< 32; i
++) {
3725 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3726 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3727 strcpyW(elf
.elfScript
, OEM_DOSW
);
3728 i
= 32; /* break out of loop */
3729 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3732 fs
.fsCsb
[0] = 1L << i
;
3734 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3736 csi
.ciCharset
= DEFAULT_CHARSET
;
3737 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3738 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3739 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3742 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3744 FIXME("Unknown elfscript for bit %d\n", i
);
3747 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3748 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3749 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3750 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3751 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3752 ntm
.ntmTm
.ntmFlags
);
3753 /* release section before callback (FIXME) */
3754 LeaveCriticalSection( &freetype_cs
);
3755 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3756 EnterCriticalSection( &freetype_cs
);
3760 LeaveCriticalSection( &freetype_cs
);
3764 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3766 pt
->x
.value
= vec
->x
>> 6;
3767 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3768 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3769 pt
->y
.value
= vec
->y
>> 6;
3770 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3771 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3775 /***************************************************
3776 * According to the MSDN documentation on WideCharToMultiByte,
3777 * certain codepages cannot set the default_used parameter.
3778 * This returns TRUE if the codepage can set that parameter, false else
3779 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3781 static BOOL
codepage_sets_default_used(UINT codepage
)
3795 * GSUB Table handling functions
3798 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
3800 const GSUB_CoverageFormat1
* cf1
;
3802 cf1
= (GSUB_CoverageFormat1
*)table
;
3804 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
3806 int count
= GET_BE_WORD(cf1
->GlyphCount
);
3808 TRACE("Coverage Format 1, %i glyphs\n",count
);
3809 for (i
= 0; i
< count
; i
++)
3810 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
3814 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
3816 const GSUB_CoverageFormat2
* cf2
;
3819 cf2
= (GSUB_CoverageFormat2
*)cf1
;
3821 count
= GET_BE_WORD(cf2
->RangeCount
);
3822 TRACE("Coverage Format 2, %i ranges\n",count
);
3823 for (i
= 0; i
< count
; i
++)
3825 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
3827 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
3828 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
3830 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
3831 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
3837 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
3842 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
3844 const GSUB_ScriptList
*script
;
3845 const GSUB_Script
*deflt
= NULL
;
3847 script
= (GSUB_ScriptList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->ScriptList
));
3849 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
3850 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
3852 const GSUB_Script
*scr
;
3855 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
3856 scr
= (GSUB_Script
*)((LPBYTE
)script
+ offset
);
3858 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
3860 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
3866 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
3870 const GSUB_LangSys
*Lang
;
3872 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
3874 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
3876 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
3877 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
3879 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
3882 offset
= GET_BE_WORD(script
->DefaultLangSys
);
3885 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
3891 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
3894 const GSUB_FeatureList
*feature
;
3895 feature
= (GSUB_FeatureList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->FeatureList
));
3897 TRACE("%i features \n",GET_BE_WORD(lang
->FeatureCount
));
3898 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
3900 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
3901 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
3903 const GSUB_Feature
*feat
;
3904 feat
= (GSUB_Feature
*)((LPBYTE
)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
3911 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
3915 const GSUB_LookupList
*lookup
;
3916 lookup
= (GSUB_LookupList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->LookupList
));
3918 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
3919 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
3921 const GSUB_LookupTable
*look
;
3922 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
3923 look
= (GSUB_LookupTable
*)((LPBYTE
)lookup
+ offset
);
3924 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
3925 if (GET_BE_WORD(look
->LookupType
) != 1)
3926 FIXME("We only handle SubType 1\n");
3931 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
3933 const GSUB_SingleSubstFormat1
*ssf1
;
3934 offset
= GET_BE_WORD(look
->SubTable
[j
]);
3935 ssf1
= (GSUB_SingleSubstFormat1
*)((LPBYTE
)look
+offset
);
3936 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
3938 int offset
= GET_BE_WORD(ssf1
->Coverage
);
3939 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
3940 if (GSUB_is_glyph_covered((LPBYTE
)ssf1
+offset
, glyph
) != -1)
3942 TRACE(" Glyph 0x%x ->",glyph
);
3943 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
3944 TRACE(" 0x%x\n",glyph
);
3949 const GSUB_SingleSubstFormat2
*ssf2
;
3953 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
3954 offset
= GET_BE_WORD(ssf1
->Coverage
);
3955 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
3956 index
= GSUB_is_glyph_covered((LPBYTE
)ssf2
+offset
, glyph
);
3957 TRACE(" Coverage index %i\n",index
);
3960 TRACE(" Glyph is 0x%x ->",glyph
);
3961 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
3962 TRACE("0x%x\n",glyph
);
3971 static const char* get_opentype_script(const GdiFont
*font
)
3974 * I am not sure if this is the correct way to generate our script tag
3977 switch (font
->charset
)
3979 case ANSI_CHARSET
: return "latn";
3980 case BALTIC_CHARSET
: return "latn"; /* ?? */
3981 case CHINESEBIG5_CHARSET
: return "hani";
3982 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
3983 case GB2312_CHARSET
: return "hani";
3984 case GREEK_CHARSET
: return "grek";
3985 case HANGUL_CHARSET
: return "hang";
3986 case RUSSIAN_CHARSET
: return "cyrl";
3987 case SHIFTJIS_CHARSET
: return "kana";
3988 case TURKISH_CHARSET
: return "latn"; /* ?? */
3989 case VIETNAMESE_CHARSET
: return "latn";
3990 case JOHAB_CHARSET
: return "latn"; /* ?? */
3991 case ARABIC_CHARSET
: return "arab";
3992 case HEBREW_CHARSET
: return "hebr";
3993 case THAI_CHARSET
: return "thai";
3994 default: return "latn";
3998 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4000 const GSUB_Header
*header
;
4001 const GSUB_Script
*script
;
4002 const GSUB_LangSys
*language
;
4003 const GSUB_Feature
*feature
;
4005 if (!font
->GSUB_Table
)
4008 header
= font
->GSUB_Table
;
4010 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4013 TRACE("Script not found\n");
4016 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4019 TRACE("Language not found\n");
4022 feature
= GSUB_get_feature(header
, language
, "vrt2");
4024 feature
= GSUB_get_feature(header
, language
, "vert");
4027 TRACE("vrt2/vert feature not found\n");
4030 return GSUB_apply_feature(header
, feature
, glyph
);
4033 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4037 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4038 WCHAR wc
= (WCHAR
)glyph
;
4040 BOOL
*default_used_pointer
;
4043 default_used_pointer
= NULL
;
4044 default_used
= FALSE
;
4045 if (codepage_sets_default_used(font
->codepage
))
4046 default_used_pointer
= &default_used
;
4047 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4050 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4051 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4052 return get_GSUB_vert_glyph(font
,ret
);
4055 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
4056 glyph
= glyph
+ 0xf000;
4057 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4058 return get_GSUB_vert_glyph(font
,glyphId
);
4061 /*************************************************************
4062 * WineEngGetGlyphIndices
4064 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
4066 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4067 LPWORD pgi
, DWORD flags
)
4070 WCHAR default_char
= 0;
4073 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0x001f; /* Indicate non existence */
4075 for(i
= 0; i
< count
; i
++)
4077 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4082 WineEngGetTextMetrics(font
, &textm
);
4083 default_char
= textm
.tmDefaultChar
;
4085 pgi
[i
] = default_char
;
4091 /*************************************************************
4092 * WineEngGetGlyphOutline
4094 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4095 * except that the first parameter is the HWINEENGFONT of the font in
4096 * question rather than an HDC.
4099 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4100 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4103 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4104 FT_Face ft_face
= incoming_font
->ft_face
;
4105 GdiFont
*font
= incoming_font
;
4106 FT_UInt glyph_index
;
4107 DWORD width
, height
, pitch
, needed
= 0;
4108 FT_Bitmap ft_bitmap
;
4110 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4112 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4113 float widthRatio
= 1.0;
4114 FT_Matrix transMat
= identityMat
;
4115 BOOL needsTransform
= FALSE
;
4116 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4117 UINT original_index
;
4120 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4121 buflen
, buf
, lpmat
);
4123 EnterCriticalSection( &freetype_cs
);
4125 if(format
& GGO_GLYPH_INDEX
) {
4126 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4127 original_index
= glyph
;
4128 format
&= ~GGO_GLYPH_INDEX
;
4130 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4131 ft_face
= font
->ft_face
;
4132 original_index
= glyph_index
;
4135 /* tategaki never appears to happen to lower glyph index */
4136 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4139 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4140 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4141 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4142 font
->gmsize
* sizeof(GM
*));
4144 if(format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&& FONT_GM(font
,original_index
)->init
) {
4145 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4146 LeaveCriticalSection( &freetype_cs
);
4147 return 1; /* FIXME */
4151 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4152 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4154 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) || lpmat
)
4155 load_flags
|= FT_LOAD_NO_BITMAP
;
4157 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4160 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4161 LeaveCriticalSection( &freetype_cs
);
4165 /* Scaling factor */
4166 if (font
->aveWidth
&& font
->potm
)
4168 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4169 widthRatio
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4172 widthRatio
= font
->scale_y
;
4174 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
4175 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
4177 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
4179 bbx
= (right
- left
) >> 6;
4181 /* Scaling transform */
4182 if(font
->aveWidth
) {
4184 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4187 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4189 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4190 needsTransform
= TRUE
;
4193 /* Slant transform */
4194 if (font
->fake_italic
) {
4197 slantMat
.xx
= (1 << 16);
4198 slantMat
.xy
= ((1 << 16) >> 2);
4200 slantMat
.yy
= (1 << 16);
4201 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4202 needsTransform
= TRUE
;
4205 /* Rotation transform */
4206 if(font
->orientation
&& !tategaki
) {
4207 FT_Matrix rotationMat
;
4209 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
4210 pFT_Vector_Unit(&vecAngle
, angle
);
4211 rotationMat
.xx
= vecAngle
.x
;
4212 rotationMat
.xy
= -vecAngle
.y
;
4213 rotationMat
.yx
= -rotationMat
.xy
;
4214 rotationMat
.yy
= rotationMat
.xx
;
4216 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4217 needsTransform
= TRUE
;
4220 /* Extra transformation specified by caller */
4223 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4224 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
4225 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
4226 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4227 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4228 needsTransform
= TRUE
;
4231 if(!needsTransform
) {
4232 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4233 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4234 ft_face
->glyph
->metrics
.height
) & -64;
4235 lpgm
->gmCellIncX
= adv
;
4236 lpgm
->gmCellIncY
= 0;
4240 for(xc
= 0; xc
< 2; xc
++) {
4241 for(yc
= 0; yc
< 2; yc
++) {
4242 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4243 xc
* ft_face
->glyph
->metrics
.width
);
4244 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4245 yc
* ft_face
->glyph
->metrics
.height
;
4246 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4247 pFT_Vector_Transform(&vec
, &transMat
);
4248 if(xc
== 0 && yc
== 0) {
4249 left
= right
= vec
.x
;
4250 top
= bottom
= vec
.y
;
4252 if(vec
.x
< left
) left
= vec
.x
;
4253 else if(vec
.x
> right
) right
= vec
.x
;
4254 if(vec
.y
< bottom
) bottom
= vec
.y
;
4255 else if(vec
.y
> top
) top
= vec
.y
;
4260 right
= (right
+ 63) & -64;
4261 bottom
= bottom
& -64;
4262 top
= (top
+ 63) & -64;
4264 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4265 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4267 pFT_Vector_Transform(&vec
, &transMat
);
4268 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4269 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4271 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4272 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4273 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4274 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4276 if(format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
)
4278 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4279 FONT_GM(font
,original_index
)->adv
= adv
;
4280 FONT_GM(font
,original_index
)->lsb
= lsb
;
4281 FONT_GM(font
,original_index
)->bbx
= bbx
;
4282 FONT_GM(font
,original_index
)->init
= TRUE
;
4285 if(format
== GGO_METRICS
)
4287 LeaveCriticalSection( &freetype_cs
);
4288 return 1; /* FIXME */
4291 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) {
4292 TRACE("loaded a bitmap\n");
4293 LeaveCriticalSection( &freetype_cs
);
4299 width
= lpgm
->gmBlackBoxX
;
4300 height
= lpgm
->gmBlackBoxY
;
4301 pitch
= ((width
+ 31) >> 5) << 2;
4302 needed
= pitch
* height
;
4304 if(!buf
|| !buflen
) break;
4306 switch(ft_face
->glyph
->format
) {
4307 case ft_glyph_format_bitmap
:
4309 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4310 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4311 INT h
= ft_face
->glyph
->bitmap
.rows
;
4313 memcpy(dst
, src
, w
);
4314 src
+= ft_face
->glyph
->bitmap
.pitch
;
4320 case ft_glyph_format_outline
:
4321 ft_bitmap
.width
= width
;
4322 ft_bitmap
.rows
= height
;
4323 ft_bitmap
.pitch
= pitch
;
4324 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4325 ft_bitmap
.buffer
= buf
;
4327 if(needsTransform
) {
4328 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4331 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4333 /* Note: FreeType will only set 'black' bits for us. */
4334 memset(buf
, 0, needed
);
4335 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4339 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4340 LeaveCriticalSection( &freetype_cs
);
4345 case GGO_GRAY2_BITMAP
:
4346 case GGO_GRAY4_BITMAP
:
4347 case GGO_GRAY8_BITMAP
:
4348 case WINE_GGO_GRAY16_BITMAP
:
4350 unsigned int mult
, row
, col
;
4353 width
= lpgm
->gmBlackBoxX
;
4354 height
= lpgm
->gmBlackBoxY
;
4355 pitch
= (width
+ 3) / 4 * 4;
4356 needed
= pitch
* height
;
4358 if(!buf
|| !buflen
) break;
4360 switch(ft_face
->glyph
->format
) {
4361 case ft_glyph_format_bitmap
:
4363 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4364 INT h
= ft_face
->glyph
->bitmap
.rows
;
4367 for(x
= 0; x
< pitch
; x
++)
4368 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
4369 src
+= ft_face
->glyph
->bitmap
.pitch
;
4372 LeaveCriticalSection( &freetype_cs
);
4375 case ft_glyph_format_outline
:
4377 ft_bitmap
.width
= width
;
4378 ft_bitmap
.rows
= height
;
4379 ft_bitmap
.pitch
= pitch
;
4380 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4381 ft_bitmap
.buffer
= buf
;
4384 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4386 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4388 memset(ft_bitmap
.buffer
, 0, buflen
);
4390 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4392 if(format
== GGO_GRAY2_BITMAP
)
4394 else if(format
== GGO_GRAY4_BITMAP
)
4396 else if(format
== GGO_GRAY8_BITMAP
)
4398 else /* format == WINE_GGO_GRAY16_BITMAP */
4400 LeaveCriticalSection( &freetype_cs
);
4406 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4407 LeaveCriticalSection( &freetype_cs
);
4412 for(row
= 0; row
< height
; row
++) {
4414 for(col
= 0; col
< width
; col
++, ptr
++) {
4415 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4424 int contour
, point
= 0, first_pt
;
4425 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4426 TTPOLYGONHEADER
*pph
;
4428 DWORD pph_start
, cpfx
, type
;
4430 if(buflen
== 0) buf
= NULL
;
4432 if (needsTransform
&& buf
) {
4433 pFT_Outline_Transform(outline
, &transMat
);
4436 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4438 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4441 pph
->dwType
= TT_POLYGON_TYPE
;
4442 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4444 needed
+= sizeof(*pph
);
4446 while(point
<= outline
->contours
[contour
]) {
4447 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4448 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4449 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
4453 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4456 } while(point
<= outline
->contours
[contour
] &&
4457 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4458 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4459 /* At the end of a contour Windows adds the start point, but
4461 if(point
> outline
->contours
[contour
] &&
4462 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4464 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
4466 } else if(point
<= outline
->contours
[contour
] &&
4467 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4468 /* add closing pt for bezier */
4470 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4478 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4481 pph
->cb
= needed
- pph_start
;
4487 /* Convert the quadratic Beziers to cubic Beziers.
4488 The parametric eqn for a cubic Bezier is, from PLRM:
4489 r(t) = at^3 + bt^2 + ct + r0
4490 with the control points:
4495 A quadratic Beizer has the form:
4496 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4498 So equating powers of t leads to:
4499 r1 = 2/3 p1 + 1/3 p0
4500 r2 = 2/3 p1 + 1/3 p2
4501 and of course r0 = p0, r3 = p2
4504 int contour
, point
= 0, first_pt
;
4505 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4506 TTPOLYGONHEADER
*pph
;
4508 DWORD pph_start
, cpfx
, type
;
4509 FT_Vector cubic_control
[4];
4510 if(buflen
== 0) buf
= NULL
;
4512 if (needsTransform
&& buf
) {
4513 pFT_Outline_Transform(outline
, &transMat
);
4516 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4518 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4521 pph
->dwType
= TT_POLYGON_TYPE
;
4522 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4524 needed
+= sizeof(*pph
);
4526 while(point
<= outline
->contours
[contour
]) {
4527 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4528 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4529 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
4532 if(type
== TT_PRIM_LINE
) {
4534 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4538 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4541 /* FIXME: Possible optimization in endpoint calculation
4542 if there are two consecutive curves */
4543 cubic_control
[0] = outline
->points
[point
-1];
4544 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4545 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
4546 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
4547 cubic_control
[0].x
>>= 1;
4548 cubic_control
[0].y
>>= 1;
4550 if(point
+1 > outline
->contours
[contour
])
4551 cubic_control
[3] = outline
->points
[first_pt
];
4553 cubic_control
[3] = outline
->points
[point
+1];
4554 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
4555 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
4556 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
4557 cubic_control
[3].x
>>= 1;
4558 cubic_control
[3].y
>>= 1;
4561 /* r1 = 1/3 p0 + 2/3 p1
4562 r2 = 1/3 p2 + 2/3 p1 */
4563 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
4564 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
4565 cubic_control
[2] = cubic_control
[1];
4566 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
4567 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
4568 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
4569 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
4571 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
4572 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
4573 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
4578 } while(point
<= outline
->contours
[contour
] &&
4579 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4580 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4581 /* At the end of a contour Windows adds the start point,
4582 but only for Beziers and we've already done that.
4584 if(point
<= outline
->contours
[contour
] &&
4585 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4586 /* This is the closing pt of a bezier, but we've already
4587 added it, so just inc point and carry on */
4594 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4597 pph
->cb
= needed
- pph_start
;
4603 FIXME("Unsupported format %d\n", format
);
4604 LeaveCriticalSection( &freetype_cs
);
4607 LeaveCriticalSection( &freetype_cs
);
4611 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
4613 FT_Face ft_face
= font
->ft_face
;
4614 #ifdef HAVE_FREETYPE_FTWINFNT_H
4615 FT_WinFNT_HeaderRec winfnt_header
;
4617 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
4618 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
4619 font
->potm
->otmSize
= size
;
4621 #define TM font->potm->otmTextMetrics
4622 #ifdef HAVE_FREETYPE_FTWINFNT_H
4623 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
4625 TM
.tmHeight
= winfnt_header
.pixel_height
;
4626 TM
.tmAscent
= winfnt_header
.ascent
;
4627 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
4628 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
4629 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
4630 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
4631 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4632 TM
.tmWeight
= winfnt_header
.weight
;
4634 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4635 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4636 TM
.tmFirstChar
= winfnt_header
.first_char
;
4637 TM
.tmLastChar
= winfnt_header
.last_char
;
4638 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4639 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4640 TM
.tmItalic
= winfnt_header
.italic
;
4641 TM
.tmUnderlined
= font
->underline
;
4642 TM
.tmStruckOut
= font
->strikeout
;
4643 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4644 TM
.tmCharSet
= winfnt_header
.charset
;
4649 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4650 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4651 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4652 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4653 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4654 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4655 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4656 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4658 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4659 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4661 TM
.tmLastChar
= 255;
4662 TM
.tmDefaultChar
= 32;
4663 TM
.tmBreakChar
= 32;
4664 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4665 TM
.tmUnderlined
= font
->underline
;
4666 TM
.tmStruckOut
= font
->strikeout
;
4667 /* NB inverted meaning of TMPF_FIXED_PITCH */
4668 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4669 TM
.tmCharSet
= font
->charset
;
4677 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
4683 scale_x
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4684 scale_x
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4687 scale_x
= font
->scale_y
;
4689 ptm
->tmHeight
= (float)ptm
->tmHeight
* font
->scale_y
;
4690 ptm
->tmAscent
= (float)ptm
->tmAscent
* font
->scale_y
;
4691 ptm
->tmDescent
= (float)ptm
->tmDescent
* font
->scale_y
;
4692 ptm
->tmInternalLeading
= (float)ptm
->tmInternalLeading
* font
->scale_y
;
4693 ptm
->tmExternalLeading
= (float)ptm
->tmExternalLeading
* font
->scale_y
;
4695 ptm
->tmAveCharWidth
= (float)ptm
->tmAveCharWidth
* scale_x
;
4696 ptm
->tmMaxCharWidth
= (float)ptm
->tmMaxCharWidth
* scale_x
;
4699 /*************************************************************
4700 * WineEngGetTextMetrics
4703 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4705 EnterCriticalSection( &freetype_cs
);
4707 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4708 if(!get_bitmap_text_metrics(font
))
4710 LeaveCriticalSection( &freetype_cs
);
4716 LeaveCriticalSection( &freetype_cs
);
4719 *ptm
= font
->potm
->otmTextMetrics
;
4720 scale_font_metrics(font
, ptm
);
4721 LeaveCriticalSection( &freetype_cs
);
4726 /*************************************************************
4727 * WineEngGetOutlineTextMetrics
4730 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4731 OUTLINETEXTMETRICW
*potm
)
4733 FT_Face ft_face
= font
->ft_face
;
4734 UINT needed
, lenfam
, lensty
, ret
;
4736 TT_HoriHeader
*pHori
;
4737 TT_Postscript
*pPost
;
4738 FT_Fixed x_scale
, y_scale
;
4739 WCHAR
*family_nameW
, *style_nameW
;
4740 static const WCHAR spaceW
[] = {' ', '\0'};
4742 INT ascent
, descent
;
4744 TRACE("font=%p\n", font
);
4746 if(!FT_IS_SCALABLE(ft_face
))
4749 EnterCriticalSection( &freetype_cs
);
4752 if(cbSize
>= font
->potm
->otmSize
)
4754 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4755 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4757 LeaveCriticalSection( &freetype_cs
);
4758 return font
->potm
->otmSize
;
4762 needed
= sizeof(*potm
);
4764 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
4765 family_nameW
= strdupW(font
->name
);
4767 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
4769 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
4770 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
4771 style_nameW
, lensty
/sizeof(WCHAR
));
4773 /* These names should be read from the TT name table */
4775 /* length of otmpFamilyName */
4778 /* length of otmpFaceName */
4779 if(!strcasecmp(ft_face
->style_name
, "regular")) {
4780 needed
+= lenfam
; /* just the family name */
4782 needed
+= lenfam
+ lensty
; /* family + " " + style */
4785 /* length of otmpStyleName */
4788 /* length of otmpFullName */
4789 needed
+= lenfam
+ lensty
;
4792 x_scale
= ft_face
->size
->metrics
.x_scale
;
4793 y_scale
= ft_face
->size
->metrics
.y_scale
;
4795 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4797 FIXME("Can't find OS/2 table - not TT font?\n");
4802 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4804 FIXME("Can't find HHEA table - not TT font?\n");
4809 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
4811 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",
4812 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
4813 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
4814 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
4815 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
4816 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
4818 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
4819 font
->potm
->otmSize
= needed
;
4821 #define TM font->potm->otmTextMetrics
4823 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
4824 ascent
= pHori
->Ascender
;
4825 descent
= -pHori
->Descender
;
4827 ascent
= pOS2
->usWinAscent
;
4828 descent
= pOS2
->usWinDescent
;
4832 TM
.tmAscent
= font
->yMax
;
4833 TM
.tmDescent
= -font
->yMin
;
4834 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4836 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4837 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4838 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4839 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4842 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4845 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4847 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4848 ((ascent
+ descent
) -
4849 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4851 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4852 if (TM
.tmAveCharWidth
== 0) {
4853 TM
.tmAveCharWidth
= 1;
4855 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4856 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4858 TM
.tmDigitizedAspectX
= 300;
4859 TM
.tmDigitizedAspectY
= 300;
4860 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4861 * symbol range to 0 - f0ff
4863 if (font
->charset
== SYMBOL_CHARSET
)
4866 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4867 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4868 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4869 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4870 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4871 TM
.tmUnderlined
= font
->underline
;
4872 TM
.tmStruckOut
= font
->strikeout
;
4874 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4875 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4876 (pOS2
->version
== 0xFFFFU
||
4877 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4878 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4880 TM
.tmPitchAndFamily
= 0;
4882 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4883 case PAN_FAMILY_SCRIPT
:
4884 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4886 case PAN_FAMILY_DECORATIVE
:
4887 case PAN_FAMILY_PICTORIAL
:
4888 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4890 case PAN_FAMILY_TEXT_DISPLAY
:
4891 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4892 TM
.tmPitchAndFamily
= FF_MODERN
;
4894 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4895 case PAN_SERIF_NORMAL_SANS
:
4896 case PAN_SERIF_OBTUSE_SANS
:
4897 case PAN_SERIF_PERP_SANS
:
4898 TM
.tmPitchAndFamily
|= FF_SWISS
;
4901 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4906 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4909 if(FT_IS_SCALABLE(ft_face
))
4910 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4912 if(FT_IS_SFNT(ft_face
))
4914 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
4915 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
4917 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4920 TM
.tmCharSet
= font
->charset
;
4923 font
->potm
->otmFiller
= 0;
4924 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4925 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4926 font
->potm
->otmfsType
= pOS2
->fsType
;
4927 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4928 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4929 font
->potm
->otmItalicAngle
= 0; /* POST table */
4930 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4931 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4932 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4933 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4934 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4935 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
4936 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4937 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
4938 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
4939 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
4940 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
4941 font
->potm
->otmMacDescent
= 0;
4942 font
->potm
->otmMacLineGap
= 0;
4943 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
4944 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
4945 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
4946 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
4947 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
4948 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
4949 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
4950 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
4951 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
4952 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
4953 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
4955 font
->potm
->otmsUnderscoreSize
= 0;
4956 font
->potm
->otmsUnderscorePosition
= 0;
4958 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
4959 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
4962 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4963 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
4964 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
4965 strcpyW((WCHAR
*)cp
, family_nameW
);
4967 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
4968 strcpyW((WCHAR
*)cp
, style_nameW
);
4970 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
4971 strcpyW((WCHAR
*)cp
, family_nameW
);
4972 if(strcasecmp(ft_face
->style_name
, "regular")) {
4973 strcatW((WCHAR
*)cp
, spaceW
);
4974 strcatW((WCHAR
*)cp
, style_nameW
);
4975 cp
+= lenfam
+ lensty
;
4978 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
4979 strcpyW((WCHAR
*)cp
, family_nameW
);
4980 strcatW((WCHAR
*)cp
, spaceW
);
4981 strcatW((WCHAR
*)cp
, style_nameW
);
4984 if(potm
&& needed
<= cbSize
)
4986 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4987 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4991 HeapFree(GetProcessHeap(), 0, style_nameW
);
4992 HeapFree(GetProcessHeap(), 0, family_nameW
);
4994 LeaveCriticalSection( &freetype_cs
);
4998 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5000 HFONTLIST
*hfontlist
;
5001 child
->font
= alloc_font();
5002 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5003 if(!child
->font
->ft_face
)
5005 free_font(child
->font
);
5010 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5011 child
->font
->orientation
= font
->orientation
;
5012 child
->font
->scale_y
= font
->scale_y
;
5013 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5014 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5015 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5016 child
->font
->base_font
= font
;
5017 list_add_head(&child_font_list
, &child
->font
->entry
);
5018 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5022 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5025 CHILD_FONT
*child_font
;
5028 font
= font
->base_font
;
5030 *linked_font
= font
;
5032 if((*glyph
= get_glyph_index(font
, c
)))
5035 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5037 if(!child_font
->font
)
5038 if(!load_child_font(font
, child_font
))
5041 if(!child_font
->font
->ft_face
)
5043 g
= get_glyph_index(child_font
->font
, c
);
5047 *linked_font
= child_font
->font
;
5054 /*************************************************************
5055 * WineEngGetCharWidth
5058 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5063 FT_UInt glyph_index
;
5064 GdiFont
*linked_font
;
5066 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5068 EnterCriticalSection( &freetype_cs
);
5069 for(c
= firstChar
; c
<= lastChar
; c
++) {
5070 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5071 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5072 &gm
, 0, NULL
, NULL
);
5073 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5075 LeaveCriticalSection( &freetype_cs
);
5079 /*************************************************************
5080 * WineEngGetCharABCWidths
5083 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5088 FT_UInt glyph_index
;
5089 GdiFont
*linked_font
;
5091 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5093 if(!FT_IS_SCALABLE(font
->ft_face
))
5096 EnterCriticalSection( &freetype_cs
);
5098 for(c
= firstChar
; c
<= lastChar
; c
++) {
5099 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5100 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5101 &gm
, 0, NULL
, NULL
);
5102 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
5103 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
5104 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
5105 FONT_GM(linked_font
,glyph_index
)->bbx
;
5107 LeaveCriticalSection( &freetype_cs
);
5111 /*************************************************************
5112 * WineEngGetCharABCWidthsI
5115 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5120 FT_UInt glyph_index
;
5121 GdiFont
*linked_font
;
5123 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
5126 EnterCriticalSection( &freetype_cs
);
5128 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
5130 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
5131 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5132 &gm
, 0, NULL
, NULL
);
5133 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
5134 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
5135 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
5136 - FONT_GM(linked_font
,c
)->bbx
;
5139 for(c
= 0; c
< count
; c
++) {
5140 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
5141 &gm
, 0, NULL
, NULL
);
5142 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
5143 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
5144 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
5145 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
5148 LeaveCriticalSection( &freetype_cs
);
5152 /*************************************************************
5153 * WineEngGetTextExtentExPoint
5156 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5157 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5163 FT_UInt glyph_index
;
5164 GdiFont
*linked_font
;
5166 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
5169 EnterCriticalSection( &freetype_cs
);
5172 WineEngGetTextMetrics(font
, &tm
);
5173 size
->cy
= tm
.tmHeight
;
5175 for(idx
= 0; idx
< count
; idx
++) {
5176 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
5177 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5178 &gm
, 0, NULL
, NULL
);
5179 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
5181 if (! pnfit
|| ext
<= max_ext
) {
5191 LeaveCriticalSection( &freetype_cs
);
5192 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5196 /*************************************************************
5197 * WineEngGetTextExtentExPointI
5200 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5201 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5208 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
5210 EnterCriticalSection( &freetype_cs
);
5213 WineEngGetTextMetrics(font
, &tm
);
5214 size
->cy
= tm
.tmHeight
;
5216 for(idx
= 0; idx
< count
; idx
++) {
5217 WineEngGetGlyphOutline(font
, indices
[idx
],
5218 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
5220 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
5222 if (! pnfit
|| ext
<= max_ext
) {
5232 LeaveCriticalSection( &freetype_cs
);
5233 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5237 /*************************************************************
5238 * WineEngGetFontData
5241 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5244 FT_Face ft_face
= font
->ft_face
;
5248 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5249 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
5250 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
5252 if(!FT_IS_SFNT(ft_face
))
5260 if(table
) { /* MS tags differ in endidness from FT ones */
5261 table
= table
>> 24 | table
<< 24 |
5262 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
5265 /* make sure value of len is the value freetype says it needs */
5268 FT_ULong needed
= 0;
5269 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
5270 if( !err
&& needed
< len
) len
= needed
;
5272 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
5275 TRACE("Can't find table %c%c%c%c\n",
5276 /* bytes were reversed */
5277 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
5278 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
5284 /*************************************************************
5285 * WineEngGetTextFace
5288 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5291 lstrcpynW(str
, font
->name
, count
);
5292 return strlenW(font
->name
);
5294 return strlenW(font
->name
) + 1;
5297 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5299 if (fs
) *fs
= font
->fs
;
5300 return font
->charset
;
5303 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5305 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
5306 struct list
*first_hfont
;
5309 EnterCriticalSection( &freetype_cs
);
5310 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
5311 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
5312 if(font
== linked_font
)
5313 *new_hfont
= dc
->hFont
;
5316 first_hfont
= list_head(&linked_font
->hfontlist
);
5317 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
5319 LeaveCriticalSection( &freetype_cs
);
5323 /* Retrieve a list of supported Unicode ranges for a given font.
5324 * Can be called with NULL gs to calculate the buffer size. Returns
5325 * the number of ranges found.
5327 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
5329 DWORD num_ranges
= 0;
5331 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5334 FT_ULong char_code
, char_code_prev
;
5337 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
5339 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5340 face
->num_glyphs
, glyph_code
, char_code
);
5342 if (!glyph_code
) return 0;
5346 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
5347 gs
->ranges
[0].cGlyphs
= 0;
5348 gs
->cGlyphsSupported
= 0;
5354 if (char_code
< char_code_prev
)
5356 ERR("expected increasing char code from FT_Get_Next_Char\n");
5359 if (char_code
- char_code_prev
> 1)
5364 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
5365 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
5366 gs
->cGlyphsSupported
++;
5371 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
5372 gs
->cGlyphsSupported
++;
5374 char_code_prev
= char_code
;
5375 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
5379 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
5384 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5387 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
5389 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
5392 glyphset
->cbThis
= size
;
5393 glyphset
->cRanges
= num_ranges
;
5398 /*************************************************************
5401 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5404 EnterCriticalSection( &freetype_cs
);
5405 ret
= !list_empty(&font
->child_fonts
);
5406 LeaveCriticalSection( &freetype_cs
);
5410 static BOOL
is_hinting_enabled(void)
5412 /* Use the >= 2.2.0 function if available */
5413 if(pFT_Get_TrueType_Engine_Type
)
5415 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
5416 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
5418 #ifdef FT_DRIVER_HAS_HINTER
5423 /* otherwise if we've been compiled with < 2.2.0 headers
5424 use the internal macro */
5425 mod
= pFT_Get_Module(library
, "truetype");
5426 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
5434 /*************************************************************************
5435 * GetRasterizerCaps (GDI32.@)
5437 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5439 static int hinting
= -1;
5443 hinting
= is_hinting_enabled();
5444 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
5447 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5448 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
5449 lprs
->nLanguageID
= 0;
5453 /*************************************************************************
5454 * Kerning support for TrueType fonts
5456 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5458 struct TT_kern_table
5464 struct TT_kern_subtable
5473 USHORT horizontal
: 1;
5475 USHORT cross_stream
: 1;
5476 USHORT override
: 1;
5477 USHORT reserved1
: 4;
5483 struct TT_format0_kern_subtable
5487 USHORT entrySelector
;
5498 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
5499 const struct TT_format0_kern_subtable
*tt_f0_ks
,
5500 const USHORT
*glyph_to_char
,
5501 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
5504 const struct TT_kern_pair
*tt_kern_pair
;
5506 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
5508 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
5510 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5511 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
5512 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
5514 if (!kern_pair
|| !cPairs
)
5517 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
5519 nPairs
= min(nPairs
, cPairs
);
5521 for (i
= 0; i
< nPairs
; i
++)
5523 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
5524 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
5525 /* this algorithm appears to better match what Windows does */
5526 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
5527 if (kern_pair
->iKernAmount
< 0)
5529 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
5530 kern_pair
->iKernAmount
-= font
->ppem
;
5532 else if (kern_pair
->iKernAmount
> 0)
5534 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
5535 kern_pair
->iKernAmount
+= font
->ppem
;
5537 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
5539 TRACE("left %u right %u value %d\n",
5540 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
5544 TRACE("copied %u entries\n", nPairs
);
5548 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5552 const struct TT_kern_table
*tt_kern_table
;
5553 const struct TT_kern_subtable
*tt_kern_subtable
;
5555 USHORT
*glyph_to_char
;
5557 EnterCriticalSection( &freetype_cs
);
5558 if (font
->total_kern_pairs
!= (DWORD
)-1)
5560 if (cPairs
&& kern_pair
)
5562 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5563 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5564 LeaveCriticalSection( &freetype_cs
);
5567 LeaveCriticalSection( &freetype_cs
);
5568 return font
->total_kern_pairs
;
5571 font
->total_kern_pairs
= 0;
5573 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
5575 if (length
== GDI_ERROR
)
5577 TRACE("no kerning data in the font\n");
5578 LeaveCriticalSection( &freetype_cs
);
5582 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
5585 WARN("Out of memory\n");
5586 LeaveCriticalSection( &freetype_cs
);
5590 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
5592 /* build a glyph index to char code map */
5593 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
5596 WARN("Out of memory allocating a glyph index to char code map\n");
5597 HeapFree(GetProcessHeap(), 0, buf
);
5598 LeaveCriticalSection( &freetype_cs
);
5602 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5608 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
5610 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5611 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
5615 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5617 /* FIXME: This doesn't match what Windows does: it does some fancy
5618 * things with duplicate glyph index to char code mappings, while
5619 * we just avoid overriding existing entries.
5621 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
5622 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
5624 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
5631 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
5632 for (n
= 0; n
<= 65535; n
++)
5633 glyph_to_char
[n
] = (USHORT
)n
;
5636 tt_kern_table
= buf
;
5637 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
5638 TRACE("version %u, nTables %u\n",
5639 GET_BE_WORD(tt_kern_table
->version
), nTables
);
5641 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
5643 for (i
= 0; i
< nTables
; i
++)
5645 struct TT_kern_subtable tt_kern_subtable_copy
;
5647 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
5648 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
5649 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
5651 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5652 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
5653 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
5655 /* According to the TrueType specification this is the only format
5656 * that will be properly interpreted by Windows and OS/2
5658 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
5660 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
5662 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5663 glyph_to_char
, NULL
, 0);
5664 font
->total_kern_pairs
+= new_chunk
;
5666 if (!font
->kern_pairs
)
5667 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
5668 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5670 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
5671 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5673 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5674 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
5677 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
5679 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
5682 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
5683 HeapFree(GetProcessHeap(), 0, buf
);
5685 if (cPairs
&& kern_pair
)
5687 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5688 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5689 LeaveCriticalSection( &freetype_cs
);
5692 LeaveCriticalSection( &freetype_cs
);
5693 return font
->total_kern_pairs
;
5696 #else /* HAVE_FREETYPE */
5698 /*************************************************************************/
5700 BOOL
WineEngInit(void)
5704 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
5708 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
5713 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5718 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
5719 LPWORD pgi
, DWORD flags
)
5724 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
5725 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5728 ERR("called but we don't have FreeType\n");
5732 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5734 ERR("called but we don't have FreeType\n");
5738 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5739 OUTLINETEXTMETRICW
*potm
)
5741 ERR("called but we don't have FreeType\n");
5745 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5748 ERR("called but we don't have FreeType\n");
5752 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5755 ERR("called but we don't have FreeType\n");
5759 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5762 ERR("called but we don't have FreeType\n");
5766 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5767 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5769 ERR("called but we don't have FreeType\n");
5773 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5774 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5776 ERR("called but we don't have FreeType\n");
5780 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5783 ERR("called but we don't have FreeType\n");
5787 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5789 ERR("called but we don't have FreeType\n");
5793 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5799 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5805 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
5811 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5814 return DEFAULT_CHARSET
;
5817 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5822 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5824 FIXME("(%p, %p): stub\n", font
, glyphset
);
5828 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5833 /*************************************************************************
5834 * GetRasterizerCaps (GDI32.@)
5836 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5838 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5840 lprs
->nLanguageID
= 0;
5844 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5846 ERR("called but we don't have FreeType\n");
5850 #endif /* HAVE_FREETYPE */