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 basically 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
;
260 FONTSIGNATURE fs_links
;
262 FT_Fixed font_version
;
264 Bitmap_Size size
; /* set if face is a bitmap */
265 BOOL external
; /* TRUE if we should manually add this font to the registry */
266 struct tagFamily
*family
;
267 /* Cached data for Enum */
268 struct enum_data
*cached_enum_data
;
271 typedef struct tagFamily
{
273 const WCHAR
*FamilyName
;
279 INT adv
; /* These three hold to widths of the unrotated chars */
297 typedef struct tagHFONTLIST
{
312 struct list hfontlist
;
313 OUTLINETEXTMETRICW
*potm
;
314 DWORD total_kern_pairs
;
315 KERNINGPAIR
*kern_pairs
;
316 struct list child_fonts
;
318 /* the following members can be accessed without locking, they are never modified after creation */
320 struct font_mapping
*mapping
;
342 const WCHAR
*font_name
;
346 #define GM_BLOCK_SIZE 128
347 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
349 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
350 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
351 #define UNUSED_CACHE_SIZE 10
352 static struct list child_font_list
= LIST_INIT(child_font_list
);
353 static struct list system_links
= LIST_INIT(system_links
);
355 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
357 static struct list font_list
= LIST_INIT(font_list
);
359 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
360 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
361 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
363 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
364 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
365 'W','i','n','d','o','w','s','\\',
366 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
367 'F','o','n','t','s','\0'};
369 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
370 'W','i','n','d','o','w','s',' ','N','T','\\',
371 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
372 'F','o','n','t','s','\0'};
374 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
375 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
376 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
377 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
379 static const WCHAR
* const SystemFontValues
[4] = {
386 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
387 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
389 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
390 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
391 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
392 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
393 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
394 'E','u','r','o','p','e','a','n','\0'};
395 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
396 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
397 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
398 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
399 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
400 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
401 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
402 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
403 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
404 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
405 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
406 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
408 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
418 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
426 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
435 typedef struct tagFontSubst
{
451 static struct list mappings_list
= LIST_INIT( mappings_list
);
453 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
455 static CRITICAL_SECTION freetype_cs
;
456 static CRITICAL_SECTION_DEBUG critsect_debug
=
459 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
460 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
462 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
464 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
466 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
467 static BOOL use_default_fallback
= FALSE
;
469 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
471 /****************************************
472 * Notes on .fon files
474 * The fonts System, FixedSys and Terminal are special. There are typically multiple
475 * versions installed for different resolutions and codepages. Windows stores which one to use
476 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
478 * FIXEDFON.FON FixedSys
480 * OEMFONT.FON Terminal
481 * LogPixels Current dpi set by the display control panel applet
482 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
483 * also has a LogPixels value that appears to mirror this)
485 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
486 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
487 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
488 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
489 * so that makes sense.
491 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
492 * to be mapped into the registry on Windows 2000 at least).
495 * ega80woa.fon=ega80850.fon
496 * ega40woa.fon=ega40850.fon
497 * cga80woa.fon=cga80850.fon
498 * cga40woa.fon=cga40850.fon
501 /* These are all structures needed for the GSUB table */
503 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
504 #define TATEGAKI_LOWER_BOUND 0x02F1
520 GSUB_ScriptRecord ScriptRecord
[1];
526 } GSUB_LangSysRecord
;
531 GSUB_LangSysRecord LangSysRecord
[1];
535 WORD LookupOrder
; /* Reserved */
536 WORD ReqFeatureIndex
;
538 WORD FeatureIndex
[1];
544 } GSUB_FeatureRecord
;
548 GSUB_FeatureRecord FeatureRecord
[1];
552 WORD FeatureParams
; /* Reserved */
554 WORD LookupListIndex
[1];
573 } GSUB_CoverageFormat1
;
578 WORD StartCoverageIndex
;
584 GSUB_RangeRecord RangeRecord
[1];
585 } GSUB_CoverageFormat2
;
588 WORD SubstFormat
; /* = 1 */
591 } GSUB_SingleSubstFormat1
;
594 WORD SubstFormat
; /* = 2 */
598 }GSUB_SingleSubstFormat2
;
600 #ifdef HAVE_CARBON_CARBON_H
601 static char *find_cache_dir(void)
605 static char cached_path
[MAX_PATH
];
606 static const char *wine
= "/Wine", *fonts
= "/Fonts";
608 if(*cached_path
) return cached_path
;
610 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
613 WARN("can't create cached data folder\n");
616 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
619 WARN("can't create cached data path\n");
623 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
625 ERR("Could not create full path\n");
629 strcat(cached_path
, wine
);
631 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
633 WARN("Couldn't mkdir %s\n", cached_path
);
637 strcat(cached_path
, fonts
);
638 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
640 WARN("Couldn't mkdir %s\n", cached_path
);
647 /******************************************************************
650 * Extracts individual TrueType font files from a Mac suitcase font
651 * and saves them into the user's caches directory (see
653 * Returns a NULL terminated array of filenames.
655 * We do this because they are apps that try to read ttf files
656 * themselves and they don't like Mac suitcase files.
658 static char **expand_mac_font(const char *path
)
665 const char *filename
;
669 unsigned int size
, max_size
;
672 TRACE("path %s\n", path
);
674 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
677 WARN("failed to get ref\n");
681 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
684 TRACE("no data fork, so trying resource fork\n");
685 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
688 TRACE("unable to open resource fork\n");
695 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
698 CloseResFile(res_ref
);
702 out_dir
= find_cache_dir();
704 filename
= strrchr(path
, '/');
705 if(!filename
) filename
= path
;
708 /* output filename has the form out_dir/filename_%04x.ttf */
709 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
716 unsigned short *num_faces_ptr
, num_faces
, face
;
719 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
721 fond
= Get1IndResource(fond_res
, idx
);
723 TRACE("got fond resource %d\n", idx
);
726 fam_rec
= *(FamRec
**)fond
;
727 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
728 num_faces
= GET_BE_WORD(*num_faces_ptr
);
730 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
731 TRACE("num faces %04x\n", num_faces
);
732 for(face
= 0; face
< num_faces
; face
++, assoc
++)
735 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
736 unsigned short size
, font_id
;
739 size
= GET_BE_WORD(assoc
->fontSize
);
740 font_id
= GET_BE_WORD(assoc
->fontID
);
743 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
747 TRACE("trying to load sfnt id %04x\n", font_id
);
748 sfnt
= GetResource(sfnt_res
, font_id
);
751 TRACE("can't get sfnt resource %04x\n", font_id
);
755 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
760 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
762 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
763 if(fd
!= -1 || errno
== EEXIST
)
767 unsigned char *sfnt_data
;
770 sfnt_data
= *(unsigned char**)sfnt
;
771 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
775 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
778 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
780 ret
.array
[ret
.size
++] = output
;
784 WARN("unable to create %s\n", output
);
785 HeapFree(GetProcessHeap(), 0, output
);
788 ReleaseResource(sfnt
);
791 ReleaseResource(fond
);
794 CloseResFile(res_ref
);
799 #endif /* HAVE_CARBON_CARBON_H */
801 static inline BOOL
is_win9x(void)
803 return GetVersion() & 0x80000000;
806 This function builds an FT_Fixed from a float. It puts the integer part
807 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
808 It fails if the integer part of the float number is greater than SHORT_MAX.
810 static inline FT_Fixed
FT_FixedFromFloat(float f
)
813 unsigned short fract
= (f
- value
) * 0xFFFF;
814 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
818 This function builds an FT_Fixed from a FIXED. It simply put f.value
819 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
821 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
823 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
827 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
832 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
833 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
835 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
836 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
838 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
840 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
842 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
846 file
= strrchr(face
->file
, '/');
851 if(!strcasecmp(file
, file_nameA
))
853 HeapFree(GetProcessHeap(), 0, file_nameA
);
858 HeapFree(GetProcessHeap(), 0, file_nameA
);
862 static Family
*find_family_from_name(const WCHAR
*name
)
866 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
868 if(!strcmpiW(family
->FamilyName
, name
))
875 static void DumpSubstList(void)
879 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
881 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
882 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
883 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
885 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
886 debugstr_w(psub
->to
.name
));
891 static LPWSTR
strdupW(LPCWSTR p
)
894 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
895 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
900 static LPSTR
strdupA(LPCSTR p
)
903 DWORD len
= (strlen(p
) + 1);
904 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
909 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
914 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
916 if(!strcmpiW(element
->from
.name
, from_name
) &&
917 (element
->from
.charset
== from_charset
||
918 element
->from
.charset
== -1))
925 #define ADD_FONT_SUBST_FORCE 1
927 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
929 FontSubst
*from_exist
, *to_exist
;
931 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
933 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
935 list_remove(&from_exist
->entry
);
936 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
937 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
938 HeapFree(GetProcessHeap(), 0, from_exist
);
944 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
948 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
949 subst
->to
.name
= strdupW(to_exist
->to
.name
);
952 list_add_tail(subst_list
, &subst
->entry
);
957 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
958 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
959 HeapFree(GetProcessHeap(), 0, subst
);
963 static void split_subst_info(NameCs
*nc
, LPSTR str
)
965 CHAR
*p
= strrchr(str
, ',');
970 nc
->charset
= strtol(p
+1, NULL
, 10);
973 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
974 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
975 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
978 static void LoadSubstList(void)
982 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
986 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
987 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
988 &hkey
) == ERROR_SUCCESS
) {
990 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
991 &valuelen
, &datalen
, NULL
, NULL
);
993 valuelen
++; /* returned value doesn't include room for '\0' */
994 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
995 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
999 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1000 &dlen
) == ERROR_SUCCESS
) {
1001 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1003 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1004 split_subst_info(&psub
->from
, value
);
1005 split_subst_info(&psub
->to
, data
);
1007 /* Win 2000 doesn't allow mapping between different charsets
1008 or mapping of DEFAULT_CHARSET */
1009 if((psub
->to
.charset
!= psub
->from
.charset
) ||
1010 psub
->to
.charset
== DEFAULT_CHARSET
) {
1011 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1012 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1013 HeapFree(GetProcessHeap(), 0, psub
);
1015 add_font_subst(&font_subst_list
, psub
, 0);
1017 /* reset dlen and vlen */
1021 HeapFree(GetProcessHeap(), 0, data
);
1022 HeapFree(GetProcessHeap(), 0, value
);
1027 static WCHAR
*get_familyname(FT_Face ft_face
)
1029 WCHAR
*family
= NULL
;
1031 FT_UInt num_names
, name_index
, i
;
1033 if(FT_IS_SFNT(ft_face
))
1035 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1037 for(name_index
= 0; name_index
< num_names
; name_index
++)
1039 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1041 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
1042 (name
.language_id
== GetUserDefaultLCID()) &&
1043 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
1044 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
1046 /* String is not nul terminated and string_len is a byte length. */
1047 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1048 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1050 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1051 family
[i
] = GET_BE_WORD(*tmp
);
1055 TRACE("Got localised name %s\n", debugstr_w(family
));
1066 /*****************************************************************
1069 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1070 * of FreeType that don't export this function.
1073 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1078 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1079 if(pFT_Load_Sfnt_Table
)
1081 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1083 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1084 else /* Do it the hard way */
1086 TT_Face tt_face
= (TT_Face
) ft_face
;
1087 SFNT_Interface
*sfnt
;
1088 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1091 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1095 /* A field was added in the middle of the structure in 2.1.x */
1096 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1098 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1106 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1107 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1108 "Please upgrade your freetype library.\n");
1111 err
= FT_Err_Unimplemented_Feature
;
1117 static inline int TestStyles(DWORD flags
, DWORD styles
)
1119 return (flags
& styles
) == styles
;
1122 static int StyleOrdering(Face
*face
)
1124 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1126 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1128 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1130 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1133 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1134 debugstr_w(face
->family
->FamilyName
),
1135 debugstr_w(face
->StyleName
),
1141 /* Add a style of face to a font family using an ordering of the list such
1142 that regular fonts come before bold and italic, and single styles come
1143 before compound styles. */
1144 static void AddFaceToFamily(Face
*face
, Family
*family
)
1148 LIST_FOR_EACH( entry
, &family
->faces
)
1150 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1151 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1153 list_add_before( entry
, &face
->entry
);
1156 #define ADDFONT_EXTERNAL_FONT 0x01
1157 #define ADDFONT_FORCE_BITMAP 0x02
1158 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1162 TT_Header
*pHeader
= NULL
;
1163 WCHAR
*english_family
, *localised_family
, *StyleW
;
1167 struct list
*family_elem_ptr
, *face_elem_ptr
;
1169 FT_Long face_index
= 0, num_faces
;
1170 #ifdef HAVE_FREETYPE_FTWINFNT_H
1171 FT_WinFNT_HeaderRec winfnt_header
;
1173 int i
, bitmap_num
, internal_leading
;
1176 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1177 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1179 #ifdef HAVE_CARBON_CARBON_H
1180 if(file
&& !fake_family
)
1182 char **mac_list
= expand_mac_font(file
);
1185 BOOL had_one
= FALSE
;
1187 for(cursor
= mac_list
; *cursor
; cursor
++)
1190 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1191 HeapFree(GetProcessHeap(), 0, *cursor
);
1193 HeapFree(GetProcessHeap(), 0, mac_list
);
1198 #endif /* HAVE_CARBON_CARBON_H */
1201 char *family_name
= fake_family
;
1205 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1206 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1209 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1210 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1214 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1218 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*/
1219 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1220 pFT_Done_Face(ft_face
);
1224 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1225 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1226 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1227 pFT_Done_Face(ft_face
);
1231 if(FT_IS_SFNT(ft_face
))
1233 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1234 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1235 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1237 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1238 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1239 pFT_Done_Face(ft_face
);
1243 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1244 we don't want to load these. */
1245 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1249 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1251 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1252 pFT_Done_Face(ft_face
);
1258 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1259 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1260 pFT_Done_Face(ft_face
);
1264 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1266 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1267 pFT_Done_Face(ft_face
);
1273 localised_family
= get_familyname(ft_face
);
1274 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1276 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1277 HeapFree(GetProcessHeap(), 0, localised_family
);
1278 num_faces
= ft_face
->num_faces
;
1279 pFT_Done_Face(ft_face
);
1282 HeapFree(GetProcessHeap(), 0, localised_family
);
1286 family_name
= ft_face
->family_name
;
1290 My_FT_Bitmap_Size
*size
= NULL
;
1293 if(!FT_IS_SCALABLE(ft_face
))
1294 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1296 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1297 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1298 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1300 localised_family
= NULL
;
1302 localised_family
= get_familyname(ft_face
);
1303 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1304 HeapFree(GetProcessHeap(), 0, localised_family
);
1305 localised_family
= NULL
;
1310 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1311 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1312 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1317 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1318 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1319 list_init(&family
->faces
);
1320 list_add_tail(&font_list
, &family
->entry
);
1322 if(localised_family
) {
1323 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1324 subst
->from
.name
= strdupW(english_family
);
1325 subst
->from
.charset
= -1;
1326 subst
->to
.name
= strdupW(localised_family
);
1327 subst
->to
.charset
= -1;
1328 add_font_subst(&font_subst_list
, subst
, 0);
1331 HeapFree(GetProcessHeap(), 0, localised_family
);
1332 HeapFree(GetProcessHeap(), 0, english_family
);
1334 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1335 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1336 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1338 internal_leading
= 0;
1339 memset(&fs
, 0, sizeof(fs
));
1341 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1343 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1344 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1345 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1346 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1347 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1348 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1349 if(pOS2
->version
== 0) {
1352 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1353 fs
.fsCsb
[0] |= FS_LATIN1
;
1355 fs
.fsCsb
[0] |= FS_SYMBOL
;
1358 #ifdef HAVE_FREETYPE_FTWINFNT_H
1359 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1361 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1362 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1363 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1365 internal_leading
= winfnt_header
.internal_leading
;
1369 face_elem_ptr
= list_head(&family
->faces
);
1370 while(face_elem_ptr
) {
1371 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1372 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1373 if(!strcmpW(face
->StyleName
, StyleW
) &&
1374 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1375 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1376 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1377 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1380 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1381 HeapFree(GetProcessHeap(), 0, StyleW
);
1382 pFT_Done_Face(ft_face
);
1385 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1386 TRACE("Original font is newer so skipping this one\n");
1387 HeapFree(GetProcessHeap(), 0, StyleW
);
1388 pFT_Done_Face(ft_face
);
1391 TRACE("Replacing original with this one\n");
1392 list_remove(&face
->entry
);
1393 HeapFree(GetProcessHeap(), 0, face
->file
);
1394 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1395 HeapFree(GetProcessHeap(), 0, face
);
1400 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1401 face
->cached_enum_data
= NULL
;
1402 face
->StyleName
= StyleW
;
1405 face
->file
= strdupA(file
);
1406 face
->font_data_ptr
= NULL
;
1407 face
->font_data_size
= 0;
1412 face
->font_data_ptr
= font_data_ptr
;
1413 face
->font_data_size
= font_data_size
;
1415 face
->face_index
= face_index
;
1417 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1418 face
->ntmFlags
|= NTM_ITALIC
;
1419 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1420 face
->ntmFlags
|= NTM_BOLD
;
1421 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1422 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1423 face
->family
= family
;
1424 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1426 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1428 if(FT_IS_SCALABLE(ft_face
)) {
1429 memset(&face
->size
, 0, sizeof(face
->size
));
1430 face
->scalable
= TRUE
;
1432 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1433 size
->height
, size
->width
, size
->size
>> 6,
1434 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1435 face
->size
.height
= size
->height
;
1436 face
->size
.width
= size
->width
;
1437 face
->size
.size
= size
->size
;
1438 face
->size
.x_ppem
= size
->x_ppem
;
1439 face
->size
.y_ppem
= size
->y_ppem
;
1440 face
->size
.internal_leading
= internal_leading
;
1441 face
->scalable
= FALSE
;
1444 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1446 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1448 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1449 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1452 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1453 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1454 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1455 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1458 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1459 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1460 switch(ft_face
->charmaps
[i
]->encoding
) {
1461 case FT_ENCODING_UNICODE
:
1462 case FT_ENCODING_APPLE_ROMAN
:
1463 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1465 case FT_ENCODING_MS_SYMBOL
:
1466 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1474 if (!(face
->fs
.fsCsb
[0] & FS_SYMBOL
))
1475 have_installed_roman_font
= TRUE
;
1477 AddFaceToFamily(face
, family
);
1479 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1481 num_faces
= ft_face
->num_faces
;
1482 pFT_Done_Face(ft_face
);
1483 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1484 debugstr_w(StyleW
));
1485 } while(num_faces
> ++face_index
);
1489 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1491 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1494 static void DumpFontList(void)
1498 struct list
*family_elem_ptr
, *face_elem_ptr
;
1500 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1501 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1502 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1503 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1504 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1505 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1507 TRACE(" %d", face
->size
.height
);
1514 /***********************************************************
1515 * The replacement list is a way to map an entire font
1516 * family onto another family. For example adding
1518 * [HKCU\Software\Wine\Fonts\Replacements]
1519 * "Wingdings"="Winedings"
1521 * would enumerate the Winedings font both as Winedings and
1522 * Wingdings. However if a real Wingdings font is present the
1523 * replacement does not take place.
1526 static void LoadReplaceList(void)
1529 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1534 struct list
*family_elem_ptr
, *face_elem_ptr
;
1537 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1538 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1540 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1541 &valuelen
, &datalen
, NULL
, NULL
);
1543 valuelen
++; /* returned value doesn't include room for '\0' */
1544 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1545 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1549 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1550 &dlen
) == ERROR_SUCCESS
) {
1551 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1552 /* "NewName"="Oldname" */
1553 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1555 /* Find the old family and hence all of the font files
1557 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1558 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1559 if(!strcmpiW(family
->FamilyName
, data
)) {
1560 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1561 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1562 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1563 debugstr_w(face
->StyleName
), familyA
);
1564 /* Now add a new entry with the new family name */
1565 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1570 /* reset dlen and vlen */
1574 HeapFree(GetProcessHeap(), 0, data
);
1575 HeapFree(GetProcessHeap(), 0, value
);
1580 /*************************************************************
1583 static BOOL
init_system_links(void)
1585 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1586 'W','i','n','d','o','w','s',' ','N','T','\\',
1587 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1588 'S','y','s','t','e','m','L','i','n','k',0};
1591 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1592 WCHAR
*value
, *data
;
1593 WCHAR
*entry
, *next
;
1594 SYSTEM_LINKS
*font_link
, *system_font_link
;
1595 CHILD_FONT
*child_font
;
1596 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1597 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1598 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1604 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1606 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1607 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1608 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1609 val_len
= max_val
+ 1;
1610 data_len
= max_data
;
1612 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1614 TRACE("%s:\n", debugstr_w(value
));
1616 memset(&fs
, 0, sizeof(fs
));
1617 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1618 psub
= get_font_subst(&font_subst_list
, value
, -1);
1619 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1620 list_init(&font_link
->links
);
1621 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1624 CHILD_FONT
*child_font
;
1626 TRACE("\t%s\n", debugstr_w(entry
));
1628 next
= entry
+ strlenW(entry
) + 1;
1630 face_name
= strchrW(entry
, ',');
1634 while(isspaceW(*face_name
))
1637 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1639 face_name
= psub
->to
.name
;
1641 face
= find_face_from_filename(entry
, face_name
);
1644 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1648 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1649 child_font
->face
= face
;
1650 child_font
->font
= NULL
;
1651 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1652 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1653 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1654 list_add_tail(&font_link
->links
, &child_font
->entry
);
1656 family
= find_family_from_name(font_link
->font_name
);
1659 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1661 face
->fs_links
= fs
;
1664 list_add_tail(&system_links
, &font_link
->entry
);
1665 val_len
= max_val
+ 1;
1666 data_len
= max_data
;
1669 HeapFree(GetProcessHeap(), 0, value
);
1670 HeapFree(GetProcessHeap(), 0, data
);
1674 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1677 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1678 system_font_link
->font_name
= strdupW(System
);
1679 list_init(&system_font_link
->links
);
1681 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1684 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1685 child_font
->face
= face
;
1686 child_font
->font
= NULL
;
1687 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1688 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1690 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1692 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1694 CHILD_FONT
*font_link_entry
;
1695 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1697 CHILD_FONT
*new_child
;
1698 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1699 new_child
->face
= font_link_entry
->face
;
1700 new_child
->font
= NULL
;
1701 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1706 list_add_tail(&system_links
, &system_font_link
->entry
);
1710 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1713 struct dirent
*dent
;
1714 char path
[MAX_PATH
];
1716 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1718 dir
= opendir(dirname
);
1720 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1723 while((dent
= readdir(dir
)) != NULL
) {
1724 struct stat statbuf
;
1726 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1729 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1731 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1733 if(stat(path
, &statbuf
) == -1)
1735 WARN("Can't stat %s\n", debugstr_a(path
));
1738 if(S_ISDIR(statbuf
.st_mode
))
1739 ReadFontDir(path
, external_fonts
);
1741 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1747 static void load_fontconfig_fonts(void)
1749 #ifdef SONAME_LIBFONTCONFIG
1750 void *fc_handle
= NULL
;
1759 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1761 TRACE("Wine cannot find the fontconfig library (%s).\n",
1762 SONAME_LIBFONTCONFIG
);
1765 #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;}
1766 LOAD_FUNCPTR(FcConfigGetCurrent
);
1767 LOAD_FUNCPTR(FcFontList
);
1768 LOAD_FUNCPTR(FcFontSetDestroy
);
1769 LOAD_FUNCPTR(FcInit
);
1770 LOAD_FUNCPTR(FcObjectSetAdd
);
1771 LOAD_FUNCPTR(FcObjectSetCreate
);
1772 LOAD_FUNCPTR(FcObjectSetDestroy
);
1773 LOAD_FUNCPTR(FcPatternCreate
);
1774 LOAD_FUNCPTR(FcPatternDestroy
);
1775 LOAD_FUNCPTR(FcPatternGetBool
);
1776 LOAD_FUNCPTR(FcPatternGetString
);
1779 if(!pFcInit()) return;
1781 config
= pFcConfigGetCurrent();
1782 pat
= pFcPatternCreate();
1783 os
= pFcObjectSetCreate();
1784 pFcObjectSetAdd(os
, FC_FILE
);
1785 pFcObjectSetAdd(os
, FC_SCALABLE
);
1786 fontset
= pFcFontList(config
, pat
, os
);
1787 if(!fontset
) return;
1788 for(i
= 0; i
< fontset
->nfont
; i
++) {
1791 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1793 TRACE("fontconfig: %s\n", file
);
1795 /* We're just interested in OT/TT fonts for now, so this hack just
1796 picks up the scalable fonts without extensions .pf[ab] to save time
1797 loading every other font */
1799 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1801 TRACE("not scalable\n");
1805 len
= strlen( file
);
1806 if(len
< 4) continue;
1807 ext
= &file
[ len
- 3 ];
1808 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1809 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1811 pFcFontSetDestroy(fontset
);
1812 pFcObjectSetDestroy(os
);
1813 pFcPatternDestroy(pat
);
1819 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1822 const char *data_dir
= wine_get_data_dir();
1824 if (!data_dir
) data_dir
= wine_get_build_dir();
1831 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1833 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1835 strcpy(unix_name
, data_dir
);
1836 strcat(unix_name
, "/fonts/");
1838 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1840 EnterCriticalSection( &freetype_cs
);
1841 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1842 LeaveCriticalSection( &freetype_cs
);
1843 HeapFree(GetProcessHeap(), 0, unix_name
);
1848 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1850 static const WCHAR slashW
[] = {'\\','\0'};
1852 WCHAR windowsdir
[MAX_PATH
];
1855 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1856 strcatW(windowsdir
, fontsW
);
1857 strcatW(windowsdir
, slashW
);
1858 strcatW(windowsdir
, file
);
1859 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1860 EnterCriticalSection( &freetype_cs
);
1861 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1862 LeaveCriticalSection( &freetype_cs
);
1863 HeapFree(GetProcessHeap(), 0, unixname
);
1868 static void load_system_fonts(void)
1871 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1872 const WCHAR
* const *value
;
1874 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1877 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1878 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1879 strcatW(windowsdir
, fontsW
);
1880 for(value
= SystemFontValues
; *value
; value
++) {
1881 dlen
= sizeof(data
);
1882 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1886 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1887 if((unixname
= wine_get_unix_file_name(pathW
))) {
1888 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1889 HeapFree(GetProcessHeap(), 0, unixname
);
1892 load_font_from_data_dir(data
);
1899 /*************************************************************
1901 * This adds registry entries for any externally loaded fonts
1902 * (fonts from fontconfig or FontDirs). It also deletes entries
1903 * of no longer existing fonts.
1906 static void update_reg_entries(void)
1908 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1913 struct list
*family_elem_ptr
, *face_elem_ptr
;
1915 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1916 static const WCHAR spaceW
[] = {' ', '\0'};
1919 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1920 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1921 ERR("Can't create Windows font reg key\n");
1925 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1926 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1927 ERR("Can't create Windows font reg key\n");
1931 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1932 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
1933 ERR("Can't create external font reg key\n");
1937 /* enumerate the fonts and add external ones to the two keys */
1939 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1940 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1941 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1942 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1943 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1944 if(!face
->external
) continue;
1946 if (!(face
->ntmFlags
& NTM_REGULAR
))
1947 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1948 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1949 strcpyW(valueW
, family
->FamilyName
);
1950 if(len
!= len_fam
) {
1951 strcatW(valueW
, spaceW
);
1952 strcatW(valueW
, face
->StyleName
);
1954 strcatW(valueW
, TrueType
);
1956 file
= wine_get_dos_file_name(face
->file
);
1958 len
= strlenW(file
) + 1;
1961 if((path
= strrchr(face
->file
, '/')) == NULL
)
1965 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1967 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1968 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1970 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1971 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1972 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1974 HeapFree(GetProcessHeap(), 0, file
);
1975 HeapFree(GetProcessHeap(), 0, valueW
);
1979 if(external_key
) RegCloseKey(external_key
);
1980 if(win9x_key
) RegCloseKey(win9x_key
);
1981 if(winnt_key
) RegCloseKey(winnt_key
);
1985 static void delete_external_font_keys(void)
1987 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1988 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
1992 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1993 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1994 ERR("Can't create Windows font reg key\n");
1998 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1999 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2000 ERR("Can't create Windows font reg key\n");
2004 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2005 ERR("Can't create external font reg key\n");
2009 /* Delete all external fonts added last time */
2011 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2012 &valuelen
, &datalen
, NULL
, NULL
);
2013 valuelen
++; /* returned value doesn't include room for '\0' */
2014 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2015 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2017 dlen
= datalen
* sizeof(WCHAR
);
2020 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2021 &dlen
) == ERROR_SUCCESS
) {
2023 RegDeleteValueW(winnt_key
, valueW
);
2024 RegDeleteValueW(win9x_key
, valueW
);
2025 /* reset dlen and vlen */
2029 HeapFree(GetProcessHeap(), 0, data
);
2030 HeapFree(GetProcessHeap(), 0, valueW
);
2032 /* Delete the old external fonts key */
2033 RegCloseKey(external_key
);
2034 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2037 if(win9x_key
) RegCloseKey(win9x_key
);
2038 if(winnt_key
) RegCloseKey(winnt_key
);
2041 /*************************************************************
2042 * WineEngAddFontResourceEx
2045 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2048 if (ft_handle
) /* do it only if we have freetype up and running */
2053 FIXME("Ignoring flags %x\n", flags
);
2055 if((unixname
= wine_get_unix_file_name(file
)))
2057 EnterCriticalSection( &freetype_cs
);
2058 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2059 LeaveCriticalSection( &freetype_cs
);
2060 HeapFree(GetProcessHeap(), 0, unixname
);
2062 if (!ret
&& !strchrW(file
, '\\')) {
2063 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2064 ret
= load_font_from_winfonts_dir(file
);
2066 /* Try in datadir/fonts (or builddir/fonts),
2067 * needed for Magic the Gathering Online
2069 ret
= load_font_from_data_dir(file
);
2076 /*************************************************************
2077 * WineEngAddFontMemResourceEx
2080 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2082 if (ft_handle
) /* do it only if we have freetype up and running */
2084 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2086 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2087 memcpy(pFontCopy
, pbFont
, cbFont
);
2089 EnterCriticalSection( &freetype_cs
);
2090 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2091 LeaveCriticalSection( &freetype_cs
);
2095 TRACE("AddFontToList failed\n");
2096 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2099 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2100 * For now return something unique but quite random
2102 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2103 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2110 /*************************************************************
2111 * WineEngRemoveFontResourceEx
2114 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2120 static const struct nls_update_font_list
2122 UINT ansi_cp
, oem_cp
;
2123 const char *oem
, *fixed
, *system
;
2124 const char *courier
, *serif
, *small
, *sserif
;
2125 /* these are for font substitute */
2126 const char *shelldlg
, *tmsrmn
;
2127 } nls_update_font_list
[] =
2129 /* Latin 1 (United States) */
2130 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2131 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2132 "Tahoma","Times New Roman",
2134 /* Latin 1 (Multilingual) */
2135 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2136 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2137 "Tahoma","Times New Roman", /* FIXME unverified */
2139 /* Eastern Europe */
2140 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2141 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2142 "Tahoma","Times New Roman", /* FIXME unverified */
2145 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2146 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2147 "Tahoma","Times New Roman", /* FIXME unverified */
2150 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2151 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2152 "Tahoma","Times New Roman", /* FIXME unverified */
2155 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2156 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2157 "Tahoma","Times New Roman", /* FIXME unverified */
2160 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2161 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2162 "Tahoma","Times New Roman", /* FIXME unverified */
2165 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2166 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2167 "Tahoma","Times New Roman", /* FIXME unverified */
2170 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2171 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2172 "Tahoma","Times New Roman", /* FIXME unverified */
2175 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2176 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2177 "Tahoma","Times New Roman", /* FIXME unverified */
2180 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2181 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2182 "Tahoma","Times New Roman", /* FIXME unverified */
2185 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2186 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2187 "MS UI Gothic","MS Serif",
2189 /* Chinese Simplified */
2190 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2191 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2192 "Tahoma", "Times New Roman", /* FIXME unverified */
2195 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2196 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2199 /* Chinese Traditional */
2200 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2201 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2202 "PMingLiU", "MingLiU",
2206 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2208 return ( ansi_cp
== 932 /* CP932 for Japanese */
2209 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2210 || ansi_cp
== 949 /* CP949 for Korean */
2211 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2214 static inline HKEY
create_fonts_NT_registry_key(void)
2218 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2219 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2223 static inline HKEY
create_fonts_9x_registry_key(void)
2227 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2228 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2232 static inline HKEY
create_config_fonts_registry_key(void)
2236 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2237 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2241 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2243 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2244 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2245 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2246 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2249 static void update_font_info(void)
2251 char buf
[40], cpbuf
[40];
2254 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2256 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2259 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2260 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2261 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2262 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2263 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2265 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2266 if (is_dbcs_ansi_cp(ansi_cp
))
2267 use_default_fallback
= TRUE
;
2270 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2272 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2277 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2279 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2281 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2284 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2286 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2287 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2291 hkey
= create_config_fonts_registry_key();
2292 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2293 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2294 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2297 hkey
= create_fonts_NT_registry_key();
2298 add_font_list(hkey
, &nls_update_font_list
[i
]);
2301 hkey
= create_fonts_9x_registry_key();
2302 add_font_list(hkey
, &nls_update_font_list
[i
]);
2305 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2307 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2308 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2309 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2310 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2316 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2320 static BOOL
init_freetype(void)
2322 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2325 "Wine cannot find the FreeType font library. To enable Wine to\n"
2326 "use TrueType fonts please install a version of FreeType greater than\n"
2327 "or equal to 2.0.5.\n"
2328 "http://www.freetype.org\n");
2332 #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;}
2334 LOAD_FUNCPTR(FT_Vector_Unit
)
2335 LOAD_FUNCPTR(FT_Done_Face
)
2336 LOAD_FUNCPTR(FT_Get_Char_Index
)
2337 LOAD_FUNCPTR(FT_Get_Module
)
2338 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2339 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2340 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2341 LOAD_FUNCPTR(FT_Init_FreeType
)
2342 LOAD_FUNCPTR(FT_Load_Glyph
)
2343 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2344 LOAD_FUNCPTR(FT_MulFix
)
2345 LOAD_FUNCPTR(FT_New_Face
)
2346 LOAD_FUNCPTR(FT_New_Memory_Face
)
2347 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2348 LOAD_FUNCPTR(FT_Outline_Transform
)
2349 LOAD_FUNCPTR(FT_Outline_Translate
)
2350 LOAD_FUNCPTR(FT_Select_Charmap
)
2351 LOAD_FUNCPTR(FT_Set_Charmap
)
2352 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2353 LOAD_FUNCPTR(FT_Vector_Transform
)
2356 /* Don't warn if these ones are missing */
2357 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2358 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2359 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2360 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2361 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2362 #ifdef HAVE_FREETYPE_FTWINFNT_H
2363 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2365 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2366 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2367 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2368 <= 2.0.3 has FT_Sqrt64 */
2372 if(pFT_Init_FreeType(&library
) != 0) {
2373 ERR("Can't init FreeType library\n");
2374 wine_dlclose(ft_handle
, NULL
, 0);
2378 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2379 if (pFT_Library_Version
)
2380 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2382 if (FT_Version
.major
<=0)
2388 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2389 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2390 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2391 ((FT_Version
.patch
) & 0x0000ff);
2397 "Wine cannot find certain functions that it needs inside the FreeType\n"
2398 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2399 "FreeType to at least version 2.0.5.\n"
2400 "http://www.freetype.org\n");
2401 wine_dlclose(ft_handle
, NULL
, 0);
2406 /*************************************************************
2409 * Initialize FreeType library and create a list of available faces
2411 BOOL
WineEngInit(void)
2413 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2414 static const WCHAR pathW
[] = {'P','a','t','h',0};
2416 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2418 WCHAR windowsdir
[MAX_PATH
];
2421 const char *data_dir
;
2425 /* update locale dependent font info in registry */
2428 if(!init_freetype()) return FALSE
;
2430 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2431 ERR("Failed to create font mutex\n");
2434 WaitForSingleObject(font_mutex
, INFINITE
);
2436 delete_external_font_keys();
2438 /* load the system bitmap fonts */
2439 load_system_fonts();
2441 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2442 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2443 strcatW(windowsdir
, fontsW
);
2444 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2446 ReadFontDir(unixname
, FALSE
);
2447 HeapFree(GetProcessHeap(), 0, unixname
);
2450 /* load the system truetype fonts */
2451 data_dir
= wine_get_data_dir();
2452 if (!data_dir
) data_dir
= wine_get_build_dir();
2453 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2454 strcpy(unixname
, data_dir
);
2455 strcat(unixname
, "/fonts/");
2456 ReadFontDir(unixname
, TRUE
);
2457 HeapFree(GetProcessHeap(), 0, unixname
);
2460 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2461 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2462 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2464 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2465 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2466 &hkey
) == ERROR_SUCCESS
) {
2468 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2469 &valuelen
, &datalen
, NULL
, NULL
);
2471 valuelen
++; /* returned value doesn't include room for '\0' */
2472 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2473 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2476 dlen
= datalen
* sizeof(WCHAR
);
2478 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2479 &dlen
) == ERROR_SUCCESS
) {
2480 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2482 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2484 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2485 HeapFree(GetProcessHeap(), 0, unixname
);
2488 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2490 WCHAR pathW
[MAX_PATH
];
2491 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2494 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2495 if((unixname
= wine_get_unix_file_name(pathW
)))
2497 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2498 HeapFree(GetProcessHeap(), 0, unixname
);
2501 load_font_from_data_dir(data
);
2503 /* reset dlen and vlen */
2508 HeapFree(GetProcessHeap(), 0, data
);
2509 HeapFree(GetProcessHeap(), 0, valueW
);
2513 load_fontconfig_fonts();
2515 /* then look in any directories that we've specified in the config file */
2516 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2517 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2523 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2525 len
+= sizeof(WCHAR
);
2526 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2527 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2529 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2530 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2531 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2532 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2536 LPSTR next
= strchr( ptr
, ':' );
2537 if (next
) *next
++ = 0;
2538 ReadFontDir( ptr
, TRUE
);
2541 HeapFree( GetProcessHeap(), 0, valueA
);
2543 HeapFree( GetProcessHeap(), 0, valueW
);
2552 update_reg_entries();
2554 init_system_links();
2556 ReleaseMutex(font_mutex
);
2561 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2564 TT_HoriHeader
*pHori
;
2568 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2569 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2571 if(height
== 0) height
= 16;
2573 /* Calc. height of EM square:
2575 * For +ve lfHeight we have
2576 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2577 * Re-arranging gives:
2578 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2580 * For -ve lfHeight we have
2582 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2583 * with il = winAscent + winDescent - units_per_em]
2588 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2589 ppem
= ft_face
->units_per_EM
* height
/
2590 (pHori
->Ascender
- pHori
->Descender
);
2592 ppem
= ft_face
->units_per_EM
* height
/
2593 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2601 static struct font_mapping
*map_font_file( const char *name
)
2603 struct font_mapping
*mapping
;
2607 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2608 if (fstat( fd
, &st
) == -1) goto error
;
2610 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2612 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2614 mapping
->refcount
++;
2619 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2622 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2625 if (mapping
->data
== MAP_FAILED
)
2627 HeapFree( GetProcessHeap(), 0, mapping
);
2630 mapping
->refcount
= 1;
2631 mapping
->dev
= st
.st_dev
;
2632 mapping
->ino
= st
.st_ino
;
2633 mapping
->size
= st
.st_size
;
2634 list_add_tail( &mappings_list
, &mapping
->entry
);
2642 static void unmap_font_file( struct font_mapping
*mapping
)
2644 if (!--mapping
->refcount
)
2646 list_remove( &mapping
->entry
);
2647 munmap( mapping
->data
, mapping
->size
);
2648 HeapFree( GetProcessHeap(), 0, mapping
);
2652 static LONG
load_VDMX(GdiFont
*, LONG
);
2654 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2661 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2665 if (!(font
->mapping
= map_font_file( face
->file
)))
2667 WARN("failed to map %s\n", debugstr_a(face
->file
));
2670 data_ptr
= font
->mapping
->data
;
2671 data_size
= font
->mapping
->size
;
2675 data_ptr
= face
->font_data_ptr
;
2676 data_size
= face
->font_data_size
;
2679 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2681 ERR("FT_New_Face rets %d\n", err
);
2685 /* set it here, as load_VDMX needs it */
2686 font
->ft_face
= ft_face
;
2688 if(FT_IS_SCALABLE(ft_face
)) {
2689 /* load the VDMX table if we have one */
2690 font
->ppem
= load_VDMX(font
, height
);
2692 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2694 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2695 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2697 font
->ppem
= height
;
2698 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2699 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2705 static int get_nearest_charset(Face
*face
, int *cp
)
2707 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2708 a single face with the requested charset. The idea is to check if
2709 the selected font supports the current ANSI codepage, if it does
2710 return the corresponding charset, else return the first charset */
2713 int acp
= GetACP(), i
;
2717 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2718 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2719 return csi
.ciCharset
;
2721 for(i
= 0; i
< 32; i
++) {
2723 if(face
->fs
.fsCsb
[0] & fs0
) {
2724 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2726 return csi
.ciCharset
;
2729 FIXME("TCI failing on %x\n", fs0
);
2733 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2734 face
->fs
.fsCsb
[0], face
->file
);
2736 return DEFAULT_CHARSET
;
2739 static GdiFont
*alloc_font(void)
2741 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2743 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2744 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2746 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2747 ret
->total_kern_pairs
= (DWORD
)-1;
2748 ret
->kern_pairs
= NULL
;
2749 list_init(&ret
->hfontlist
);
2750 list_init(&ret
->child_fonts
);
2754 static void free_font(GdiFont
*font
)
2756 struct list
*cursor
, *cursor2
;
2759 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2761 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2762 struct list
*first_hfont
;
2763 HFONTLIST
*hfontlist
;
2764 list_remove(cursor
);
2767 first_hfont
= list_head(&child
->font
->hfontlist
);
2768 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2769 DeleteObject(hfontlist
->hfont
);
2770 HeapFree(GetProcessHeap(), 0, hfontlist
);
2771 free_font(child
->font
);
2773 HeapFree(GetProcessHeap(), 0, child
);
2776 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2777 if (font
->mapping
) unmap_font_file( font
->mapping
);
2778 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2779 HeapFree(GetProcessHeap(), 0, font
->potm
);
2780 HeapFree(GetProcessHeap(), 0, font
->name
);
2781 for (i
= 0; i
< font
->gmsize
; i
++)
2782 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2783 HeapFree(GetProcessHeap(), 0, font
->gm
);
2784 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
2785 HeapFree(GetProcessHeap(), 0, font
);
2789 /*************************************************************
2792 * load the vdmx entry for the specified height
2795 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2796 ( ( (FT_ULong)_x4 << 24 ) | \
2797 ( (FT_ULong)_x3 << 16 ) | \
2798 ( (FT_ULong)_x2 << 8 ) | \
2801 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2816 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2820 BYTE devXRatio
, devYRatio
;
2821 USHORT numRecs
, numRatios
;
2822 DWORD result
, offset
= -1;
2826 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2828 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2831 /* FIXME: need the real device aspect ratio */
2835 numRecs
= GET_BE_WORD(hdr
[1]);
2836 numRatios
= GET_BE_WORD(hdr
[2]);
2838 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2839 for(i
= 0; i
< numRatios
; i
++) {
2842 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2843 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2846 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2848 if((ratio
.xRatio
== 0 &&
2849 ratio
.yStartRatio
== 0 &&
2850 ratio
.yEndRatio
== 0) ||
2851 (devXRatio
== ratio
.xRatio
&&
2852 devYRatio
>= ratio
.yStartRatio
&&
2853 devYRatio
<= ratio
.yEndRatio
))
2855 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2856 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2857 offset
= GET_BE_WORD(tmp
);
2863 FIXME("No suitable ratio found\n");
2867 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2869 BYTE startsz
, endsz
;
2872 recs
= GET_BE_WORD(group
.recs
);
2873 startsz
= group
.startsz
;
2874 endsz
= group
.endsz
;
2876 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2878 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2879 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2880 if(result
== GDI_ERROR
) {
2881 FIXME("Failed to retrieve vTable\n");
2886 for(i
= 0; i
< recs
; i
++) {
2887 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2888 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2889 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2891 if(yMax
+ -yMin
== height
) {
2894 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2897 if(yMax
+ -yMin
> height
) {
2900 goto end
; /* failed */
2902 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2903 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2904 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2905 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2911 TRACE("ppem not found for height %d\n", height
);
2915 if(ppem
< startsz
|| ppem
> endsz
)
2918 for(i
= 0; i
< recs
; i
++) {
2920 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2922 if(yPelHeight
> ppem
)
2925 if(yPelHeight
== ppem
) {
2926 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2927 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2928 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2934 HeapFree(GetProcessHeap(), 0, vTable
);
2940 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
2942 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2943 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2944 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2945 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2946 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2949 static void calc_hash(FONT_DESC
*pfd
)
2951 DWORD hash
= 0, *ptr
, two_chars
;
2955 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2957 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2959 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2961 pwc
= (WCHAR
*)&two_chars
;
2963 *pwc
= toupperW(*pwc
);
2965 *pwc
= toupperW(*pwc
);
2969 hash
^= !pfd
->can_use_bitmap
;
2974 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const XFORM
*pxf
, BOOL can_use_bitmap
)
2979 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2982 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2983 fd
.can_use_bitmap
= can_use_bitmap
;
2986 /* try the in-use list */
2987 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2988 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2989 if(!fontcmp(ret
, &fd
)) {
2990 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2991 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2992 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2993 if(hflist
->hfont
== hfont
)
2996 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2997 hflist
->hfont
= hfont
;
2998 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3003 /* then the unused list */
3004 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3005 while(font_elem_ptr
) {
3006 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3007 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3008 if(!fontcmp(ret
, &fd
)) {
3009 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3010 assert(list_empty(&ret
->hfontlist
));
3011 TRACE("Found %p in unused list\n", ret
);
3012 list_remove(&ret
->entry
);
3013 list_add_head(&gdi_font_list
, &ret
->entry
);
3014 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3015 hflist
->hfont
= hfont
;
3016 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3024 /*************************************************************
3025 * create_child_font_list
3027 static BOOL
create_child_font_list(GdiFont
*font
)
3030 SYSTEM_LINKS
*font_link
;
3031 CHILD_FONT
*font_link_entry
, *new_child
;
3033 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3035 if(!strcmpW(font_link
->font_name
, font
->name
))
3037 TRACE("found entry in system list\n");
3038 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3040 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3041 new_child
->face
= font_link_entry
->face
;
3042 new_child
->font
= NULL
;
3043 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3044 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3051 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3052 * Sans Serif. This is how asian windows get default fallbacks for fonts
3054 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3055 font
->charset
!= OEM_CHARSET
&&
3056 strcmpW(font
->name
,szDefaultFallbackLink
) != 0)
3057 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3059 if(!strcmpW(font_link
->font_name
,szDefaultFallbackLink
))
3061 TRACE("found entry in default fallback list\n");
3062 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3064 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3065 new_child
->face
= font_link_entry
->face
;
3066 new_child
->font
= NULL
;
3067 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3068 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3078 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3080 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3082 if (pFT_Set_Charmap
)
3085 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3087 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3089 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3091 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3093 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3094 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3096 switch (ft_face
->charmaps
[i
]->platform_id
)
3099 cmap_def
= ft_face
->charmaps
[i
];
3101 case 0: /* Apple Unicode */
3102 cmap0
= ft_face
->charmaps
[i
];
3104 case 1: /* Macintosh */
3105 cmap1
= ft_face
->charmaps
[i
];
3108 cmap2
= ft_face
->charmaps
[i
];
3110 case 3: /* Microsoft */
3111 cmap3
= ft_face
->charmaps
[i
];
3116 if (cmap3
) /* prefer Microsoft cmap table */
3117 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3119 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3121 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3123 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3125 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3127 return ft_err
== FT_Err_Ok
;
3130 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3133 /*************************************************************
3134 * WineEngCreateFontInstance
3137 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3140 Face
*face
, *best
, *best_bitmap
;
3141 Family
*family
, *last_resort_family
;
3142 struct list
*family_elem_ptr
, *face_elem_ptr
;
3143 INT height
, width
= 0;
3144 unsigned int score
= 0, new_score
;
3145 signed int diff
= 0, newdiff
;
3146 BOOL bd
, it
, can_use_bitmap
;
3151 EnterCriticalSection( &freetype_cs
);
3153 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
3155 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
3156 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3157 if(hflist
->hfont
== hfont
)
3159 LeaveCriticalSection( &freetype_cs
);
3164 if (!GetObjectW( hfont
, sizeof(lf
), &lf
))
3166 LeaveCriticalSection( &freetype_cs
);
3169 lf
.lfWidth
= abs(lf
.lfWidth
);
3171 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3173 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3174 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3175 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3178 /* check the cache first */
3179 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
3180 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3181 LeaveCriticalSection( &freetype_cs
);
3185 TRACE("not in cache\n");
3186 if(list_empty(&font_list
)) /* No fonts installed */
3188 TRACE("No fonts installed\n");
3189 LeaveCriticalSection( &freetype_cs
);
3192 if(!have_installed_roman_font
)
3194 TRACE("No roman font installed\n");
3195 LeaveCriticalSection( &freetype_cs
);
3201 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3202 ret
->font_desc
.lf
= lf
;
3203 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3204 calc_hash(&ret
->font_desc
);
3205 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3206 hflist
->hfont
= hfont
;
3207 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3210 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3211 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3212 original value lfCharSet. Note this is a special case for
3213 Symbol and doesn't happen at least for "Wingdings*" */
3215 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3216 lf
.lfCharSet
= SYMBOL_CHARSET
;
3218 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3219 switch(lf
.lfCharSet
) {
3220 case DEFAULT_CHARSET
:
3221 csi
.fs
.fsCsb
[0] = 0;
3224 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3225 csi
.fs
.fsCsb
[0] = 0;
3231 if(lf
.lfFaceName
[0] != '\0') {
3233 SYSTEM_LINKS
*font_link
;
3234 CHILD_FONT
*font_link_entry
;
3235 LPWSTR FaceName
= lf
.lfFaceName
;
3238 * Check for a leading '@' this signals that the font is being
3239 * requested in tategaki mode (vertical writing substitution) but
3240 * does not affect the fontface that is to be selected.
3242 if (lf
.lfFaceName
[0]=='@')
3243 FaceName
= &lf
.lfFaceName
[1];
3245 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3248 TRACE("substituting %s -> %s\n", debugstr_w(FaceName
),
3249 debugstr_w(psub
->to
.name
));
3250 strcpyW(FaceName
, psub
->to
.name
);
3253 /* We want a match on name and charset or just name if
3254 charset was DEFAULT_CHARSET. If the latter then
3255 we fixup the returned charset later in get_nearest_charset
3256 where we'll either use the charset of the current ansi codepage
3257 or if that's unavailable the first charset that the font supports.
3259 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3260 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3261 if(!strcmpiW(family
->FamilyName
, FaceName
)) {
3262 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3263 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3264 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3265 if(face
->scalable
|| can_use_bitmap
)
3272 * Try check the SystemLink list first for a replacement font.
3273 * We may find good replacements there.
3275 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3277 if(!strcmpiW(font_link
->font_name
, FaceName
))
3279 TRACE("found entry in system list\n");
3280 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3282 face
= font_link_entry
->face
;
3283 family
= face
->family
;
3284 if(csi
.fs
.fsCsb
[0] &
3285 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3287 if(face
->scalable
|| can_use_bitmap
)
3295 /* If requested charset was DEFAULT_CHARSET then try using charset
3296 corresponding to the current ansi codepage */
3297 if (!csi
.fs
.fsCsb
[0] || lf
.lfWeight
== FW_DONTCARE
)
3300 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3301 FIXME("TCI failed on codepage %d\n", acp
);
3302 csi
.fs
.fsCsb
[0] = 0;
3304 lf
.lfCharSet
= csi
.ciCharset
;
3307 /* Face families are in the top 4 bits of lfPitchAndFamily,
3308 so mask with 0xF0 before testing */
3310 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3311 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3312 strcpyW(lf
.lfFaceName
, defFixed
);
3313 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3314 strcpyW(lf
.lfFaceName
, defSerif
);
3315 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3316 strcpyW(lf
.lfFaceName
, defSans
);
3318 strcpyW(lf
.lfFaceName
, defSans
);
3319 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3320 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3321 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3322 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3323 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3324 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3325 if(face
->scalable
|| can_use_bitmap
)
3331 last_resort_family
= NULL
;
3332 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3333 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3334 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3335 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3336 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3339 if(can_use_bitmap
&& !last_resort_family
)
3340 last_resort_family
= family
;
3345 if(last_resort_family
) {
3346 family
= last_resort_family
;
3347 csi
.fs
.fsCsb
[0] = 0;
3351 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3352 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3353 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3354 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3355 if(face
->scalable
) {
3356 csi
.fs
.fsCsb
[0] = 0;
3357 WARN("just using first face for now\n");
3360 if(can_use_bitmap
&& !last_resort_family
)
3361 last_resort_family
= family
;
3364 if(!last_resort_family
) {
3365 FIXME("can't find a single appropriate font - bailing\n");
3367 LeaveCriticalSection( &freetype_cs
);
3371 WARN("could only find a bitmap font - this will probably look awful!\n");
3372 family
= last_resort_family
;
3373 csi
.fs
.fsCsb
[0] = 0;
3376 it
= lf
.lfItalic
? 1 : 0;
3377 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3379 height
= GDI_ROUND( (double)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
3380 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
3382 face
= best
= best_bitmap
= NULL
;
3383 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3385 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3389 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3390 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3391 new_score
= (italic
^ it
) + (bold
^ bd
);
3392 if(!best
|| new_score
<= score
)
3394 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3395 italic
, bold
, it
, bd
);
3398 if(best
->scalable
&& score
== 0) break;
3402 newdiff
= height
- (signed int)(best
->size
.height
);
3404 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3405 if(!best_bitmap
|| new_score
< score
||
3406 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3408 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3411 if(score
== 0 && diff
== 0) break;
3418 face
= best
->scalable
? best
: best_bitmap
;
3419 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3420 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3424 if(csi
.fs
.fsCsb
[0]) {
3425 ret
->charset
= lf
.lfCharSet
;
3426 ret
->codepage
= csi
.ciACP
;
3429 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3431 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3432 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3434 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3436 if(!face
->scalable
) {
3437 /* Windows uses integer scaling factors for bitmap fonts */
3438 INT scale
, scaled_height
;
3440 if (height
!= 0) height
= diff
;
3441 height
+= face
->size
.height
;
3443 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3444 scaled_height
= scale
* face
->size
.height
;
3445 /* XP allows not more than 10% deviation */
3446 if (scale
> 1 && scaled_height
- height
> scaled_height
/ 10) scale
--;
3447 ret
->scale_y
= scale
;
3449 width
= face
->size
.x_ppem
>> 6;
3450 height
= face
->size
.y_ppem
>> 6;
3454 TRACE("font scale y: %f\n", ret
->scale_y
);
3456 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3461 LeaveCriticalSection( &freetype_cs
);
3465 ret
->ntmFlags
= face
->ntmFlags
;
3467 if (ret
->charset
== SYMBOL_CHARSET
&&
3468 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3471 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3475 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3478 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3479 ret
->name
= strdupW(family
->FamilyName
);
3480 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3481 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3482 create_child_font_list(ret
);
3484 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3486 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3487 if (length
!= GDI_ERROR
)
3489 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3490 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3491 TRACE("Loaded GSUB table of %i bytes\n",length
);
3495 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3497 list_add_head(&gdi_font_list
, &ret
->entry
);
3498 LeaveCriticalSection( &freetype_cs
);
3502 static void dump_gdi_font_list(void)
3505 struct list
*elem_ptr
;
3507 TRACE("---------- gdiFont Cache ----------\n");
3508 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3509 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3510 TRACE("gdiFont=%p %s %d\n",
3511 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3514 TRACE("---------- Unused gdiFont Cache ----------\n");
3515 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3516 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3517 TRACE("gdiFont=%p %s %d\n",
3518 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3522 /*************************************************************
3523 * WineEngDestroyFontInstance
3525 * free the gdiFont associated with this handle
3528 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3533 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3536 EnterCriticalSection( &freetype_cs
);
3538 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3540 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3541 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3542 if(hflist
->hfont
== handle
)
3544 TRACE("removing child font %p from child list\n", gdiFont
);
3545 list_remove(&gdiFont
->entry
);
3546 LeaveCriticalSection( &freetype_cs
);
3551 TRACE("destroying hfont=%p\n", handle
);
3553 dump_gdi_font_list();
3555 font_elem_ptr
= list_head(&gdi_font_list
);
3556 while(font_elem_ptr
) {
3557 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3558 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3560 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3561 while(hfontlist_elem_ptr
) {
3562 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3563 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3564 if(hflist
->hfont
== handle
) {
3565 list_remove(&hflist
->entry
);
3566 HeapFree(GetProcessHeap(), 0, hflist
);
3570 if(list_empty(&gdiFont
->hfontlist
)) {
3571 TRACE("Moving to Unused list\n");
3572 list_remove(&gdiFont
->entry
);
3573 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3578 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3579 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3580 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3581 while(font_elem_ptr
) {
3582 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3583 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3584 TRACE("freeing %p\n", gdiFont
);
3585 list_remove(&gdiFont
->entry
);
3588 LeaveCriticalSection( &freetype_cs
);
3592 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3593 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3598 if (face
->cached_enum_data
)
3601 *pelf
= face
->cached_enum_data
->elf
;
3602 *pntm
= face
->cached_enum_data
->ntm
;
3603 *ptype
= face
->cached_enum_data
->type
;
3607 font
= alloc_font();
3609 if(face
->scalable
) {
3610 height
= -2048; /* 2048 is the most common em size */
3613 height
= face
->size
.y_ppem
>> 6;
3614 width
= face
->size
.x_ppem
>> 6;
3616 font
->scale_y
= 1.0;
3618 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3624 font
->name
= strdupW(face
->family
->FamilyName
);
3625 font
->ntmFlags
= face
->ntmFlags
;
3627 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3629 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3631 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3633 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3634 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3636 lstrcpynW(pelf
->elfFullName
,
3637 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
3639 lstrcpynW(pelf
->elfStyle
,
3640 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
3645 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
3647 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3649 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3650 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
3651 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
3654 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
3655 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3656 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3657 pntm
->ntmFontSig
= face
->fs
;
3659 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3661 pelf
->elfLogFont
.lfEscapement
= 0;
3662 pelf
->elfLogFont
.lfOrientation
= 0;
3663 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
3664 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3665 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
3666 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
3667 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
3668 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
3669 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
3670 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3671 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3672 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3673 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3676 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
3677 *ptype
|= TRUETYPE_FONTTYPE
;
3678 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
3679 *ptype
|= DEVICE_FONTTYPE
;
3680 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
3681 *ptype
|= RASTER_FONTTYPE
;
3683 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
3684 if (face
->cached_enum_data
)
3686 face
->cached_enum_data
->elf
= *pelf
;
3687 face
->cached_enum_data
->ntm
= *pntm
;
3688 face
->cached_enum_data
->type
= *ptype
;
3694 /*************************************************************
3698 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3702 struct list
*family_elem_ptr
, *face_elem_ptr
;
3704 NEWTEXTMETRICEXW ntm
;
3713 lf
.lfCharSet
= DEFAULT_CHARSET
;
3714 lf
.lfPitchAndFamily
= 0;
3715 lf
.lfFaceName
[0] = 0;
3719 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3721 EnterCriticalSection( &freetype_cs
);
3722 if(plf
->lfFaceName
[0]) {
3724 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3727 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3728 debugstr_w(psub
->to
.name
));
3730 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3734 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3735 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3736 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3737 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3738 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3739 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3740 for(i
= 0; i
< 32; i
++) {
3741 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3742 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3743 strcpyW(elf
.elfScript
, OEM_DOSW
);
3744 i
= 32; /* break out of loop */
3745 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3748 fs
.fsCsb
[0] = 1L << i
;
3750 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3752 csi
.ciCharset
= DEFAULT_CHARSET
;
3753 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3754 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3755 elf
.elfLogFont
.lfCharSet
=
3756 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3758 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3760 FIXME("Unknown elfscript for bit %d\n", i
);
3763 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3764 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3765 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3766 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3767 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3768 ntm
.ntmTm
.ntmFlags
);
3769 /* release section before callback (FIXME) */
3770 LeaveCriticalSection( &freetype_cs
);
3771 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3772 EnterCriticalSection( &freetype_cs
);
3778 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3779 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3780 face_elem_ptr
= list_head(&family
->faces
);
3781 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3782 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3783 for(i
= 0; i
< 32; i
++) {
3784 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3785 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3786 strcpyW(elf
.elfScript
, OEM_DOSW
);
3787 i
= 32; /* break out of loop */
3788 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3791 fs
.fsCsb
[0] = 1L << i
;
3793 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3795 csi
.ciCharset
= DEFAULT_CHARSET
;
3796 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3797 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3798 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3801 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3803 FIXME("Unknown elfscript for bit %d\n", i
);
3806 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3807 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3808 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3809 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3810 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3811 ntm
.ntmTm
.ntmFlags
);
3812 /* release section before callback (FIXME) */
3813 LeaveCriticalSection( &freetype_cs
);
3814 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3815 EnterCriticalSection( &freetype_cs
);
3819 LeaveCriticalSection( &freetype_cs
);
3823 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3825 pt
->x
.value
= vec
->x
>> 6;
3826 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3827 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3828 pt
->y
.value
= vec
->y
>> 6;
3829 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3830 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3834 /***************************************************
3835 * According to the MSDN documentation on WideCharToMultiByte,
3836 * certain codepages cannot set the default_used parameter.
3837 * This returns TRUE if the codepage can set that parameter, false else
3838 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3840 static BOOL
codepage_sets_default_used(UINT codepage
)
3854 * GSUB Table handling functions
3857 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
3859 const GSUB_CoverageFormat1
* cf1
;
3861 cf1
= (GSUB_CoverageFormat1
*)table
;
3863 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
3865 int count
= GET_BE_WORD(cf1
->GlyphCount
);
3867 TRACE("Coverage Format 1, %i glyphs\n",count
);
3868 for (i
= 0; i
< count
; i
++)
3869 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
3873 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
3875 const GSUB_CoverageFormat2
* cf2
;
3878 cf2
= (GSUB_CoverageFormat2
*)cf1
;
3880 count
= GET_BE_WORD(cf2
->RangeCount
);
3881 TRACE("Coverage Format 2, %i ranges\n",count
);
3882 for (i
= 0; i
< count
; i
++)
3884 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
3886 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
3887 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
3889 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
3890 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
3896 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
3901 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
3903 const GSUB_ScriptList
*script
;
3904 const GSUB_Script
*deflt
= NULL
;
3906 script
= (GSUB_ScriptList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->ScriptList
));
3908 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
3909 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
3911 const GSUB_Script
*scr
;
3914 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
3915 scr
= (GSUB_Script
*)((LPBYTE
)script
+ offset
);
3917 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
3919 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
3925 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
3929 const GSUB_LangSys
*Lang
;
3931 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
3933 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
3935 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
3936 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
3938 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
3941 offset
= GET_BE_WORD(script
->DefaultLangSys
);
3944 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
3950 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
3953 const GSUB_FeatureList
*feature
;
3954 feature
= (GSUB_FeatureList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->FeatureList
));
3956 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
3957 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
3959 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
3960 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
3962 const GSUB_Feature
*feat
;
3963 feat
= (GSUB_Feature
*)((LPBYTE
)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
3970 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
3974 const GSUB_LookupList
*lookup
;
3975 lookup
= (GSUB_LookupList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->LookupList
));
3977 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
3978 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
3980 const GSUB_LookupTable
*look
;
3981 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
3982 look
= (GSUB_LookupTable
*)((LPBYTE
)lookup
+ offset
);
3983 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
3984 if (GET_BE_WORD(look
->LookupType
) != 1)
3985 FIXME("We only handle SubType 1\n");
3990 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
3992 const GSUB_SingleSubstFormat1
*ssf1
;
3993 offset
= GET_BE_WORD(look
->SubTable
[j
]);
3994 ssf1
= (GSUB_SingleSubstFormat1
*)((LPBYTE
)look
+offset
);
3995 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
3997 int offset
= GET_BE_WORD(ssf1
->Coverage
);
3998 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
3999 if (GSUB_is_glyph_covered((LPBYTE
)ssf1
+offset
, glyph
) != -1)
4001 TRACE(" Glyph 0x%x ->",glyph
);
4002 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4003 TRACE(" 0x%x\n",glyph
);
4008 const GSUB_SingleSubstFormat2
*ssf2
;
4012 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
4013 offset
= GET_BE_WORD(ssf1
->Coverage
);
4014 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4015 index
= GSUB_is_glyph_covered((LPBYTE
)ssf2
+offset
, glyph
);
4016 TRACE(" Coverage index %i\n",index
);
4019 TRACE(" Glyph is 0x%x ->",glyph
);
4020 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4021 TRACE("0x%x\n",glyph
);
4030 static const char* get_opentype_script(const GdiFont
*font
)
4033 * I am not sure if this is the correct way to generate our script tag
4036 switch (font
->charset
)
4038 case ANSI_CHARSET
: return "latn";
4039 case BALTIC_CHARSET
: return "latn"; /* ?? */
4040 case CHINESEBIG5_CHARSET
: return "hani";
4041 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4042 case GB2312_CHARSET
: return "hani";
4043 case GREEK_CHARSET
: return "grek";
4044 case HANGUL_CHARSET
: return "hang";
4045 case RUSSIAN_CHARSET
: return "cyrl";
4046 case SHIFTJIS_CHARSET
: return "kana";
4047 case TURKISH_CHARSET
: return "latn"; /* ?? */
4048 case VIETNAMESE_CHARSET
: return "latn";
4049 case JOHAB_CHARSET
: return "latn"; /* ?? */
4050 case ARABIC_CHARSET
: return "arab";
4051 case HEBREW_CHARSET
: return "hebr";
4052 case THAI_CHARSET
: return "thai";
4053 default: return "latn";
4057 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4059 const GSUB_Header
*header
;
4060 const GSUB_Script
*script
;
4061 const GSUB_LangSys
*language
;
4062 const GSUB_Feature
*feature
;
4064 if (!font
->GSUB_Table
)
4067 header
= font
->GSUB_Table
;
4069 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4072 TRACE("Script not found\n");
4075 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4078 TRACE("Language not found\n");
4081 feature
= GSUB_get_feature(header
, language
, "vrt2");
4083 feature
= GSUB_get_feature(header
, language
, "vert");
4086 TRACE("vrt2/vert feature not found\n");
4089 return GSUB_apply_feature(header
, feature
, glyph
);
4092 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4096 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4097 WCHAR wc
= (WCHAR
)glyph
;
4099 BOOL
*default_used_pointer
;
4102 default_used_pointer
= NULL
;
4103 default_used
= FALSE
;
4104 if (codepage_sets_default_used(font
->codepage
))
4105 default_used_pointer
= &default_used
;
4106 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4109 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4110 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4111 return get_GSUB_vert_glyph(font
,ret
);
4114 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
&& glyph
< 0x100)
4115 glyph
= glyph
+ 0xf000;
4116 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4117 return get_GSUB_vert_glyph(font
,glyphId
);
4120 /*************************************************************
4121 * WineEngGetGlyphIndices
4124 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4125 LPWORD pgi
, DWORD flags
)
4128 int default_char
= -1;
4130 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4132 for(i
= 0; i
< count
; i
++)
4134 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4137 if (default_char
== -1)
4139 if (FT_IS_SFNT(font
->ft_face
))
4141 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4142 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4147 WineEngGetTextMetrics(font
, &textm
);
4148 default_char
= textm
.tmDefaultChar
;
4151 pgi
[i
] = default_char
;
4157 /*************************************************************
4158 * WineEngGetGlyphOutline
4160 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4161 * except that the first parameter is the HWINEENGFONT of the font in
4162 * question rather than an HDC.
4165 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4166 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4169 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4170 FT_Face ft_face
= incoming_font
->ft_face
;
4171 GdiFont
*font
= incoming_font
;
4172 FT_UInt glyph_index
;
4173 DWORD width
, height
, pitch
, needed
= 0;
4174 FT_Bitmap ft_bitmap
;
4176 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4178 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4179 float widthRatio
= 1.0;
4180 FT_Matrix transMat
= identityMat
;
4181 BOOL needsTransform
= FALSE
;
4182 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4183 UINT original_index
;
4186 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4187 buflen
, buf
, lpmat
);
4189 EnterCriticalSection( &freetype_cs
);
4191 if(format
& GGO_GLYPH_INDEX
) {
4192 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4193 original_index
= glyph
;
4194 format
&= ~GGO_GLYPH_INDEX
;
4196 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4197 ft_face
= font
->ft_face
;
4198 original_index
= glyph_index
;
4201 /* tategaki never appears to happen to lower glyph index */
4202 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4205 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4206 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4207 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4208 font
->gmsize
* sizeof(GM
*));
4210 if(format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&& FONT_GM(font
,original_index
)->init
) {
4211 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4212 LeaveCriticalSection( &freetype_cs
);
4213 return 1; /* FIXME */
4217 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4218 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4220 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) || lpmat
)
4221 load_flags
|= FT_LOAD_NO_BITMAP
;
4223 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4226 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4227 LeaveCriticalSection( &freetype_cs
);
4231 /* Scaling factor */
4232 if (font
->aveWidth
&& font
->potm
)
4234 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4235 widthRatio
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4238 widthRatio
= font
->scale_y
;
4240 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
4241 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
4243 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
4245 bbx
= (right
- left
) >> 6;
4247 /* Scaling transform */
4248 if(font
->aveWidth
) {
4250 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4253 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4255 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4256 needsTransform
= TRUE
;
4259 /* Slant transform */
4260 if (font
->fake_italic
) {
4263 slantMat
.xx
= (1 << 16);
4264 slantMat
.xy
= ((1 << 16) >> 2);
4266 slantMat
.yy
= (1 << 16);
4267 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4268 needsTransform
= TRUE
;
4271 /* Rotation transform */
4272 if(font
->orientation
&& !tategaki
) {
4273 FT_Matrix rotationMat
;
4275 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
4276 pFT_Vector_Unit(&vecAngle
, angle
);
4277 rotationMat
.xx
= vecAngle
.x
;
4278 rotationMat
.xy
= -vecAngle
.y
;
4279 rotationMat
.yx
= -rotationMat
.xy
;
4280 rotationMat
.yy
= rotationMat
.xx
;
4282 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4283 needsTransform
= TRUE
;
4286 /* Extra transformation specified by caller */
4289 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4290 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
4291 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
4292 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4293 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4294 needsTransform
= TRUE
;
4297 if(!needsTransform
) {
4298 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4299 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4300 ft_face
->glyph
->metrics
.height
) & -64;
4301 lpgm
->gmCellIncX
= adv
;
4302 lpgm
->gmCellIncY
= 0;
4306 for(xc
= 0; xc
< 2; xc
++) {
4307 for(yc
= 0; yc
< 2; yc
++) {
4308 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4309 xc
* ft_face
->glyph
->metrics
.width
);
4310 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4311 yc
* ft_face
->glyph
->metrics
.height
;
4312 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4313 pFT_Vector_Transform(&vec
, &transMat
);
4314 if(xc
== 0 && yc
== 0) {
4315 left
= right
= vec
.x
;
4316 top
= bottom
= vec
.y
;
4318 if(vec
.x
< left
) left
= vec
.x
;
4319 else if(vec
.x
> right
) right
= vec
.x
;
4320 if(vec
.y
< bottom
) bottom
= vec
.y
;
4321 else if(vec
.y
> top
) top
= vec
.y
;
4326 right
= (right
+ 63) & -64;
4327 bottom
= bottom
& -64;
4328 top
= (top
+ 63) & -64;
4330 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4331 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4333 pFT_Vector_Transform(&vec
, &transMat
);
4334 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4335 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4337 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4338 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4339 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4340 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4342 if(format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
)
4344 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4345 FONT_GM(font
,original_index
)->adv
= adv
;
4346 FONT_GM(font
,original_index
)->lsb
= lsb
;
4347 FONT_GM(font
,original_index
)->bbx
= bbx
;
4348 FONT_GM(font
,original_index
)->init
= TRUE
;
4351 if(format
== GGO_METRICS
)
4353 LeaveCriticalSection( &freetype_cs
);
4354 return 1; /* FIXME */
4357 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) {
4358 TRACE("loaded a bitmap\n");
4359 LeaveCriticalSection( &freetype_cs
);
4365 width
= lpgm
->gmBlackBoxX
;
4366 height
= lpgm
->gmBlackBoxY
;
4367 pitch
= ((width
+ 31) >> 5) << 2;
4368 needed
= pitch
* height
;
4370 if(!buf
|| !buflen
) break;
4372 switch(ft_face
->glyph
->format
) {
4373 case ft_glyph_format_bitmap
:
4375 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4376 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4377 INT h
= ft_face
->glyph
->bitmap
.rows
;
4379 memcpy(dst
, src
, w
);
4380 src
+= ft_face
->glyph
->bitmap
.pitch
;
4386 case ft_glyph_format_outline
:
4387 ft_bitmap
.width
= width
;
4388 ft_bitmap
.rows
= height
;
4389 ft_bitmap
.pitch
= pitch
;
4390 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4391 ft_bitmap
.buffer
= buf
;
4393 if(needsTransform
) {
4394 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4397 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4399 /* Note: FreeType will only set 'black' bits for us. */
4400 memset(buf
, 0, needed
);
4401 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4405 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4406 LeaveCriticalSection( &freetype_cs
);
4411 case GGO_GRAY2_BITMAP
:
4412 case GGO_GRAY4_BITMAP
:
4413 case GGO_GRAY8_BITMAP
:
4414 case WINE_GGO_GRAY16_BITMAP
:
4416 unsigned int mult
, row
, col
;
4419 width
= lpgm
->gmBlackBoxX
;
4420 height
= lpgm
->gmBlackBoxY
;
4421 pitch
= (width
+ 3) / 4 * 4;
4422 needed
= pitch
* height
;
4424 if(!buf
|| !buflen
) break;
4426 switch(ft_face
->glyph
->format
) {
4427 case ft_glyph_format_bitmap
:
4429 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4430 INT h
= ft_face
->glyph
->bitmap
.rows
;
4433 for(x
= 0; x
< pitch
; x
++)
4435 if(x
< ft_face
->glyph
->bitmap
.width
)
4436 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
4440 src
+= ft_face
->glyph
->bitmap
.pitch
;
4443 LeaveCriticalSection( &freetype_cs
);
4446 case ft_glyph_format_outline
:
4448 ft_bitmap
.width
= width
;
4449 ft_bitmap
.rows
= height
;
4450 ft_bitmap
.pitch
= pitch
;
4451 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4452 ft_bitmap
.buffer
= buf
;
4455 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4457 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4459 memset(ft_bitmap
.buffer
, 0, buflen
);
4461 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4463 if(format
== GGO_GRAY2_BITMAP
)
4465 else if(format
== GGO_GRAY4_BITMAP
)
4467 else if(format
== GGO_GRAY8_BITMAP
)
4469 else /* format == WINE_GGO_GRAY16_BITMAP */
4471 LeaveCriticalSection( &freetype_cs
);
4477 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4478 LeaveCriticalSection( &freetype_cs
);
4483 for(row
= 0; row
< height
; row
++) {
4485 for(col
= 0; col
< width
; col
++, ptr
++) {
4486 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4495 int contour
, point
= 0, first_pt
;
4496 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4497 TTPOLYGONHEADER
*pph
;
4499 DWORD pph_start
, cpfx
, type
;
4501 if(buflen
== 0) buf
= NULL
;
4503 if (needsTransform
&& buf
) {
4504 pFT_Outline_Transform(outline
, &transMat
);
4507 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4509 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4512 pph
->dwType
= TT_POLYGON_TYPE
;
4513 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4515 needed
+= sizeof(*pph
);
4517 while(point
<= outline
->contours
[contour
]) {
4518 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4519 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4520 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
4524 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4527 } while(point
<= outline
->contours
[contour
] &&
4528 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4529 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4530 /* At the end of a contour Windows adds the start point, but
4532 if(point
> outline
->contours
[contour
] &&
4533 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4535 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
4537 } else if(point
<= outline
->contours
[contour
] &&
4538 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4539 /* add closing pt for bezier */
4541 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4549 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4552 pph
->cb
= needed
- pph_start
;
4558 /* Convert the quadratic Beziers to cubic Beziers.
4559 The parametric eqn for a cubic Bezier is, from PLRM:
4560 r(t) = at^3 + bt^2 + ct + r0
4561 with the control points:
4566 A quadratic Beizer has the form:
4567 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4569 So equating powers of t leads to:
4570 r1 = 2/3 p1 + 1/3 p0
4571 r2 = 2/3 p1 + 1/3 p2
4572 and of course r0 = p0, r3 = p2
4575 int contour
, point
= 0, first_pt
;
4576 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4577 TTPOLYGONHEADER
*pph
;
4579 DWORD pph_start
, cpfx
, type
;
4580 FT_Vector cubic_control
[4];
4581 if(buflen
== 0) buf
= NULL
;
4583 if (needsTransform
&& buf
) {
4584 pFT_Outline_Transform(outline
, &transMat
);
4587 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4589 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4592 pph
->dwType
= TT_POLYGON_TYPE
;
4593 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4595 needed
+= sizeof(*pph
);
4597 while(point
<= outline
->contours
[contour
]) {
4598 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4599 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4600 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
4603 if(type
== TT_PRIM_LINE
) {
4605 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4609 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4612 /* FIXME: Possible optimization in endpoint calculation
4613 if there are two consecutive curves */
4614 cubic_control
[0] = outline
->points
[point
-1];
4615 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4616 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
4617 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
4618 cubic_control
[0].x
>>= 1;
4619 cubic_control
[0].y
>>= 1;
4621 if(point
+1 > outline
->contours
[contour
])
4622 cubic_control
[3] = outline
->points
[first_pt
];
4624 cubic_control
[3] = outline
->points
[point
+1];
4625 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
4626 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
4627 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
4628 cubic_control
[3].x
>>= 1;
4629 cubic_control
[3].y
>>= 1;
4632 /* r1 = 1/3 p0 + 2/3 p1
4633 r2 = 1/3 p2 + 2/3 p1 */
4634 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
4635 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
4636 cubic_control
[2] = cubic_control
[1];
4637 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
4638 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
4639 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
4640 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
4642 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
4643 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
4644 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
4649 } while(point
<= outline
->contours
[contour
] &&
4650 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4651 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4652 /* At the end of a contour Windows adds the start point,
4653 but only for Beziers and we've already done that.
4655 if(point
<= outline
->contours
[contour
] &&
4656 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4657 /* This is the closing pt of a bezier, but we've already
4658 added it, so just inc point and carry on */
4665 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4668 pph
->cb
= needed
- pph_start
;
4674 FIXME("Unsupported format %d\n", format
);
4675 LeaveCriticalSection( &freetype_cs
);
4678 LeaveCriticalSection( &freetype_cs
);
4682 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
4684 FT_Face ft_face
= font
->ft_face
;
4685 #ifdef HAVE_FREETYPE_FTWINFNT_H
4686 FT_WinFNT_HeaderRec winfnt_header
;
4688 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
4689 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
4690 font
->potm
->otmSize
= size
;
4692 #define TM font->potm->otmTextMetrics
4693 #ifdef HAVE_FREETYPE_FTWINFNT_H
4694 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
4696 TM
.tmHeight
= winfnt_header
.pixel_height
;
4697 TM
.tmAscent
= winfnt_header
.ascent
;
4698 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
4699 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
4700 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
4701 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
4702 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4703 TM
.tmWeight
= winfnt_header
.weight
;
4705 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4706 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4707 TM
.tmFirstChar
= winfnt_header
.first_char
;
4708 TM
.tmLastChar
= winfnt_header
.last_char
;
4709 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4710 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4711 TM
.tmItalic
= winfnt_header
.italic
;
4712 TM
.tmUnderlined
= font
->underline
;
4713 TM
.tmStruckOut
= font
->strikeout
;
4714 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4715 TM
.tmCharSet
= winfnt_header
.charset
;
4720 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4721 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4722 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4723 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4724 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4725 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4726 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4727 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4729 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4730 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4732 TM
.tmLastChar
= 255;
4733 TM
.tmDefaultChar
= 32;
4734 TM
.tmBreakChar
= 32;
4735 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4736 TM
.tmUnderlined
= font
->underline
;
4737 TM
.tmStruckOut
= font
->strikeout
;
4738 /* NB inverted meaning of TMPF_FIXED_PITCH */
4739 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4740 TM
.tmCharSet
= font
->charset
;
4748 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
4754 scale_x
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4755 scale_x
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4758 scale_x
= font
->scale_y
;
4760 ptm
->tmHeight
= (float)ptm
->tmHeight
* font
->scale_y
;
4761 ptm
->tmAscent
= (float)ptm
->tmAscent
* font
->scale_y
;
4762 ptm
->tmDescent
= (float)ptm
->tmDescent
* font
->scale_y
;
4763 ptm
->tmInternalLeading
= (float)ptm
->tmInternalLeading
* font
->scale_y
;
4764 ptm
->tmExternalLeading
= (float)ptm
->tmExternalLeading
* font
->scale_y
;
4766 ptm
->tmAveCharWidth
= (float)ptm
->tmAveCharWidth
* scale_x
;
4767 ptm
->tmMaxCharWidth
= (float)ptm
->tmMaxCharWidth
* scale_x
;
4770 /*************************************************************
4771 * WineEngGetTextMetrics
4774 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4776 EnterCriticalSection( &freetype_cs
);
4778 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4779 if(!get_bitmap_text_metrics(font
))
4781 LeaveCriticalSection( &freetype_cs
);
4787 LeaveCriticalSection( &freetype_cs
);
4790 *ptm
= font
->potm
->otmTextMetrics
;
4791 scale_font_metrics(font
, ptm
);
4792 LeaveCriticalSection( &freetype_cs
);
4797 /*************************************************************
4798 * WineEngGetOutlineTextMetrics
4801 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4802 OUTLINETEXTMETRICW
*potm
)
4804 FT_Face ft_face
= font
->ft_face
;
4805 UINT needed
, lenfam
, lensty
, ret
;
4807 TT_HoriHeader
*pHori
;
4808 TT_Postscript
*pPost
;
4809 FT_Fixed x_scale
, y_scale
;
4810 WCHAR
*family_nameW
, *style_nameW
;
4811 static const WCHAR spaceW
[] = {' ', '\0'};
4813 INT ascent
, descent
;
4815 TRACE("font=%p\n", font
);
4817 if(!FT_IS_SCALABLE(ft_face
))
4820 EnterCriticalSection( &freetype_cs
);
4823 if(cbSize
>= font
->potm
->otmSize
)
4825 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4826 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4828 LeaveCriticalSection( &freetype_cs
);
4829 return font
->potm
->otmSize
;
4833 needed
= sizeof(*potm
);
4835 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
4836 family_nameW
= strdupW(font
->name
);
4838 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
4840 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
4841 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
4842 style_nameW
, lensty
/sizeof(WCHAR
));
4844 /* These names should be read from the TT name table */
4846 /* length of otmpFamilyName */
4849 /* length of otmpFaceName */
4850 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
4851 needed
+= lenfam
; /* just the family name */
4853 needed
+= lenfam
+ lensty
; /* family + " " + style */
4856 /* length of otmpStyleName */
4859 /* length of otmpFullName */
4860 needed
+= lenfam
+ lensty
;
4863 x_scale
= ft_face
->size
->metrics
.x_scale
;
4864 y_scale
= ft_face
->size
->metrics
.y_scale
;
4866 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4868 FIXME("Can't find OS/2 table - not TT font?\n");
4873 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4875 FIXME("Can't find HHEA table - not TT font?\n");
4880 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
4882 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",
4883 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
4884 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
4885 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
4886 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
4887 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
4889 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
4890 font
->potm
->otmSize
= needed
;
4892 #define TM font->potm->otmTextMetrics
4894 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
4895 ascent
= pHori
->Ascender
;
4896 descent
= -pHori
->Descender
;
4898 ascent
= pOS2
->usWinAscent
;
4899 descent
= pOS2
->usWinDescent
;
4903 TM
.tmAscent
= font
->yMax
;
4904 TM
.tmDescent
= -font
->yMin
;
4905 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4907 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4908 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4909 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4910 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4913 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4916 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4918 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4919 ((ascent
+ descent
) -
4920 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4922 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4923 if (TM
.tmAveCharWidth
== 0) {
4924 TM
.tmAveCharWidth
= 1;
4926 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4927 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4929 TM
.tmDigitizedAspectX
= 300;
4930 TM
.tmDigitizedAspectY
= 300;
4931 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4932 * symbol range to 0 - f0ff
4934 if (font
->charset
== SYMBOL_CHARSET
)
4937 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4941 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4942 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0xffff;
4944 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4945 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4946 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4947 TM
.tmUnderlined
= font
->underline
;
4948 TM
.tmStruckOut
= font
->strikeout
;
4950 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4951 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4952 (pOS2
->version
== 0xFFFFU
||
4953 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4954 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4956 TM
.tmPitchAndFamily
= 0;
4958 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4959 case PAN_FAMILY_SCRIPT
:
4960 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4962 case PAN_FAMILY_DECORATIVE
:
4963 case PAN_FAMILY_PICTORIAL
:
4964 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4966 case PAN_FAMILY_TEXT_DISPLAY
:
4967 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4968 TM
.tmPitchAndFamily
= FF_MODERN
;
4970 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4971 case PAN_SERIF_NORMAL_SANS
:
4972 case PAN_SERIF_OBTUSE_SANS
:
4973 case PAN_SERIF_PERP_SANS
:
4974 TM
.tmPitchAndFamily
|= FF_SWISS
;
4977 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4982 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4985 if(FT_IS_SCALABLE(ft_face
))
4986 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4988 if(FT_IS_SFNT(ft_face
))
4990 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
4991 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
4993 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4996 TM
.tmCharSet
= font
->charset
;
4999 font
->potm
->otmFiller
= 0;
5000 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
5001 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
5002 font
->potm
->otmfsType
= pOS2
->fsType
;
5003 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
5004 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
5005 font
->potm
->otmItalicAngle
= 0; /* POST table */
5006 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
5007 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
5008 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
5009 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
5010 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
5011 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5012 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5013 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5014 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5015 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5016 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
5017 font
->potm
->otmMacDescent
= 0;
5018 font
->potm
->otmMacLineGap
= 0;
5019 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5020 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5021 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5022 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5023 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5024 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5025 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5026 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5027 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5028 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5029 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5031 font
->potm
->otmsUnderscoreSize
= 0;
5032 font
->potm
->otmsUnderscorePosition
= 0;
5034 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5035 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5038 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5039 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5040 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5041 strcpyW((WCHAR
*)cp
, family_nameW
);
5043 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5044 strcpyW((WCHAR
*)cp
, style_nameW
);
5046 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5047 strcpyW((WCHAR
*)cp
, family_nameW
);
5048 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
5049 strcatW((WCHAR
*)cp
, spaceW
);
5050 strcatW((WCHAR
*)cp
, style_nameW
);
5051 cp
+= lenfam
+ lensty
;
5054 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5055 strcpyW((WCHAR
*)cp
, family_nameW
);
5056 strcatW((WCHAR
*)cp
, spaceW
);
5057 strcatW((WCHAR
*)cp
, style_nameW
);
5060 if(potm
&& needed
<= cbSize
)
5062 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5063 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5067 HeapFree(GetProcessHeap(), 0, style_nameW
);
5068 HeapFree(GetProcessHeap(), 0, family_nameW
);
5070 LeaveCriticalSection( &freetype_cs
);
5074 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5076 HFONTLIST
*hfontlist
;
5077 child
->font
= alloc_font();
5078 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5079 if(!child
->font
->ft_face
)
5081 free_font(child
->font
);
5086 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5087 child
->font
->orientation
= font
->orientation
;
5088 child
->font
->scale_y
= font
->scale_y
;
5089 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5090 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5091 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5092 child
->font
->base_font
= font
;
5093 list_add_head(&child_font_list
, &child
->font
->entry
);
5094 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5098 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5101 CHILD_FONT
*child_font
;
5104 font
= font
->base_font
;
5106 *linked_font
= font
;
5108 if((*glyph
= get_glyph_index(font
, c
)))
5111 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5113 if(!child_font
->font
)
5114 if(!load_child_font(font
, child_font
))
5117 if(!child_font
->font
->ft_face
)
5119 g
= get_glyph_index(child_font
->font
, c
);
5123 *linked_font
= child_font
->font
;
5130 /*************************************************************
5131 * WineEngGetCharWidth
5134 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5139 FT_UInt glyph_index
;
5140 GdiFont
*linked_font
;
5142 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5144 EnterCriticalSection( &freetype_cs
);
5145 for(c
= firstChar
; c
<= lastChar
; c
++) {
5146 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5147 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5148 &gm
, 0, NULL
, NULL
);
5149 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5151 LeaveCriticalSection( &freetype_cs
);
5155 /*************************************************************
5156 * WineEngGetCharABCWidths
5159 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5164 FT_UInt glyph_index
;
5165 GdiFont
*linked_font
;
5167 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5169 if(!FT_IS_SCALABLE(font
->ft_face
))
5172 EnterCriticalSection( &freetype_cs
);
5174 for(c
= firstChar
; c
<= lastChar
; c
++) {
5175 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5176 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5177 &gm
, 0, NULL
, NULL
);
5178 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
5179 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
5180 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
5181 FONT_GM(linked_font
,glyph_index
)->bbx
;
5183 LeaveCriticalSection( &freetype_cs
);
5187 /*************************************************************
5188 * WineEngGetCharABCWidthsI
5191 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5196 FT_UInt glyph_index
;
5197 GdiFont
*linked_font
;
5199 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
5202 EnterCriticalSection( &freetype_cs
);
5204 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
5206 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
5207 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5208 &gm
, 0, NULL
, NULL
);
5209 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
5210 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
5211 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
5212 - FONT_GM(linked_font
,c
)->bbx
;
5215 for(c
= 0; c
< count
; c
++) {
5216 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
5217 &gm
, 0, NULL
, NULL
);
5218 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
5219 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
5220 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
5221 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
5224 LeaveCriticalSection( &freetype_cs
);
5228 /*************************************************************
5229 * WineEngGetTextExtentExPoint
5232 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5233 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5239 FT_UInt glyph_index
;
5240 GdiFont
*linked_font
;
5242 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
5245 EnterCriticalSection( &freetype_cs
);
5248 WineEngGetTextMetrics(font
, &tm
);
5249 size
->cy
= tm
.tmHeight
;
5251 for(idx
= 0; idx
< count
; idx
++) {
5252 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
5253 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5254 &gm
, 0, NULL
, NULL
);
5255 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
5257 if (! pnfit
|| ext
<= max_ext
) {
5267 LeaveCriticalSection( &freetype_cs
);
5268 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5272 /*************************************************************
5273 * WineEngGetTextExtentExPointI
5276 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5277 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5284 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
5286 EnterCriticalSection( &freetype_cs
);
5289 WineEngGetTextMetrics(font
, &tm
);
5290 size
->cy
= tm
.tmHeight
;
5292 for(idx
= 0; idx
< count
; idx
++) {
5293 WineEngGetGlyphOutline(font
, indices
[idx
],
5294 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
5296 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
5298 if (! pnfit
|| ext
<= max_ext
) {
5308 LeaveCriticalSection( &freetype_cs
);
5309 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5313 /*************************************************************
5314 * WineEngGetFontData
5317 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5320 FT_Face ft_face
= font
->ft_face
;
5324 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5325 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
5326 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
5328 if(!FT_IS_SFNT(ft_face
))
5336 if(table
) { /* MS tags differ in endianness from FT ones */
5337 table
= table
>> 24 | table
<< 24 |
5338 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
5341 /* make sure value of len is the value freetype says it needs */
5344 FT_ULong needed
= 0;
5345 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
5346 if( !err
&& needed
< len
) len
= needed
;
5348 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
5351 TRACE("Can't find table %c%c%c%c\n",
5352 /* bytes were reversed */
5353 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
5354 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
5360 /*************************************************************
5361 * WineEngGetTextFace
5364 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5367 lstrcpynW(str
, font
->name
, count
);
5368 return strlenW(font
->name
);
5370 return strlenW(font
->name
) + 1;
5373 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5375 if (fs
) *fs
= font
->fs
;
5376 return font
->charset
;
5379 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5381 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
5382 struct list
*first_hfont
;
5385 EnterCriticalSection( &freetype_cs
);
5386 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
5387 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
5388 if(font
== linked_font
)
5389 *new_hfont
= dc
->hFont
;
5392 first_hfont
= list_head(&linked_font
->hfontlist
);
5393 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
5395 LeaveCriticalSection( &freetype_cs
);
5399 /* Retrieve a list of supported Unicode ranges for a given font.
5400 * Can be called with NULL gs to calculate the buffer size. Returns
5401 * the number of ranges found.
5403 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
5405 DWORD num_ranges
= 0;
5407 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5410 FT_ULong char_code
, char_code_prev
;
5413 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
5415 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5416 face
->num_glyphs
, glyph_code
, char_code
);
5418 if (!glyph_code
) return 0;
5422 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
5423 gs
->ranges
[0].cGlyphs
= 0;
5424 gs
->cGlyphsSupported
= 0;
5430 if (char_code
< char_code_prev
)
5432 ERR("expected increasing char code from FT_Get_Next_Char\n");
5435 if (char_code
- char_code_prev
> 1)
5440 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
5441 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
5442 gs
->cGlyphsSupported
++;
5447 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
5448 gs
->cGlyphsSupported
++;
5450 char_code_prev
= char_code
;
5451 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
5455 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
5460 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5463 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
5465 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
5468 glyphset
->cbThis
= size
;
5469 glyphset
->cRanges
= num_ranges
;
5474 /*************************************************************
5477 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5480 EnterCriticalSection( &freetype_cs
);
5481 ret
= !list_empty(&font
->child_fonts
);
5482 LeaveCriticalSection( &freetype_cs
);
5486 static BOOL
is_hinting_enabled(void)
5488 /* Use the >= 2.2.0 function if available */
5489 if(pFT_Get_TrueType_Engine_Type
)
5491 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
5492 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
5494 #ifdef FT_DRIVER_HAS_HINTER
5499 /* otherwise if we've been compiled with < 2.2.0 headers
5500 use the internal macro */
5501 mod
= pFT_Get_Module(library
, "truetype");
5502 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
5510 /*************************************************************************
5511 * GetRasterizerCaps (GDI32.@)
5513 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5515 static int hinting
= -1;
5519 hinting
= is_hinting_enabled();
5520 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
5523 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5524 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
5525 lprs
->nLanguageID
= 0;
5529 /*************************************************************************
5530 * Kerning support for TrueType fonts
5532 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5534 struct TT_kern_table
5540 struct TT_kern_subtable
5549 USHORT horizontal
: 1;
5551 USHORT cross_stream
: 1;
5552 USHORT override
: 1;
5553 USHORT reserved1
: 4;
5559 struct TT_format0_kern_subtable
5563 USHORT entrySelector
;
5574 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
5575 const struct TT_format0_kern_subtable
*tt_f0_ks
,
5576 const USHORT
*glyph_to_char
,
5577 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
5580 const struct TT_kern_pair
*tt_kern_pair
;
5582 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
5584 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
5586 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5587 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
5588 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
5590 if (!kern_pair
|| !cPairs
)
5593 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
5595 nPairs
= min(nPairs
, cPairs
);
5597 for (i
= 0; i
< nPairs
; i
++)
5599 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
5600 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
5601 /* this algorithm appears to better match what Windows does */
5602 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
5603 if (kern_pair
->iKernAmount
< 0)
5605 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
5606 kern_pair
->iKernAmount
-= font
->ppem
;
5608 else if (kern_pair
->iKernAmount
> 0)
5610 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
5611 kern_pair
->iKernAmount
+= font
->ppem
;
5613 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
5615 TRACE("left %u right %u value %d\n",
5616 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
5620 TRACE("copied %u entries\n", nPairs
);
5624 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5628 const struct TT_kern_table
*tt_kern_table
;
5629 const struct TT_kern_subtable
*tt_kern_subtable
;
5631 USHORT
*glyph_to_char
;
5633 EnterCriticalSection( &freetype_cs
);
5634 if (font
->total_kern_pairs
!= (DWORD
)-1)
5636 if (cPairs
&& kern_pair
)
5638 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5639 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5640 LeaveCriticalSection( &freetype_cs
);
5643 LeaveCriticalSection( &freetype_cs
);
5644 return font
->total_kern_pairs
;
5647 font
->total_kern_pairs
= 0;
5649 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
5651 if (length
== GDI_ERROR
)
5653 TRACE("no kerning data in the font\n");
5654 LeaveCriticalSection( &freetype_cs
);
5658 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
5661 WARN("Out of memory\n");
5662 LeaveCriticalSection( &freetype_cs
);
5666 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
5668 /* build a glyph index to char code map */
5669 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
5672 WARN("Out of memory allocating a glyph index to char code map\n");
5673 HeapFree(GetProcessHeap(), 0, buf
);
5674 LeaveCriticalSection( &freetype_cs
);
5678 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5684 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
5686 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5687 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
5691 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5693 /* FIXME: This doesn't match what Windows does: it does some fancy
5694 * things with duplicate glyph index to char code mappings, while
5695 * we just avoid overriding existing entries.
5697 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
5698 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
5700 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
5707 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
5708 for (n
= 0; n
<= 65535; n
++)
5709 glyph_to_char
[n
] = (USHORT
)n
;
5712 tt_kern_table
= buf
;
5713 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
5714 TRACE("version %u, nTables %u\n",
5715 GET_BE_WORD(tt_kern_table
->version
), nTables
);
5717 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
5719 for (i
= 0; i
< nTables
; i
++)
5721 struct TT_kern_subtable tt_kern_subtable_copy
;
5723 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
5724 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
5725 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
5727 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5728 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
5729 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
5731 /* According to the TrueType specification this is the only format
5732 * that will be properly interpreted by Windows and OS/2
5734 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
5736 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
5738 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5739 glyph_to_char
, NULL
, 0);
5740 font
->total_kern_pairs
+= new_chunk
;
5742 if (!font
->kern_pairs
)
5743 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
5744 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5746 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
5747 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5749 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5750 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
5753 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
5755 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
5758 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
5759 HeapFree(GetProcessHeap(), 0, buf
);
5761 if (cPairs
&& kern_pair
)
5763 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5764 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5765 LeaveCriticalSection( &freetype_cs
);
5768 LeaveCriticalSection( &freetype_cs
);
5769 return font
->total_kern_pairs
;
5772 #else /* HAVE_FREETYPE */
5774 /*************************************************************************/
5776 BOOL
WineEngInit(void)
5780 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
5784 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
5789 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5794 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
5795 LPWORD pgi
, DWORD flags
)
5800 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
5801 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5804 ERR("called but we don't have FreeType\n");
5808 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5810 ERR("called but we don't have FreeType\n");
5814 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5815 OUTLINETEXTMETRICW
*potm
)
5817 ERR("called but we don't have FreeType\n");
5821 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5824 ERR("called but we don't have FreeType\n");
5828 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5831 ERR("called but we don't have FreeType\n");
5835 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5838 ERR("called but we don't have FreeType\n");
5842 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5843 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5845 ERR("called but we don't have FreeType\n");
5849 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5850 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5852 ERR("called but we don't have FreeType\n");
5856 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5859 ERR("called but we don't have FreeType\n");
5863 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5865 ERR("called but we don't have FreeType\n");
5869 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5875 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5881 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
5887 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5890 return DEFAULT_CHARSET
;
5893 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5898 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5900 FIXME("(%p, %p): stub\n", font
, glyphset
);
5904 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5909 /*************************************************************************
5910 * GetRasterizerCaps (GDI32.@)
5912 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5914 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5916 lprs
->nLanguageID
= 0;
5920 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5922 ERR("called but we don't have FreeType\n");
5926 #endif /* HAVE_FREETYPE */