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 RegularW
[] = {'R','e','g','u','l','a','r','\0'};
365 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
366 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
367 'W','i','n','d','o','w','s','\\',
368 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
369 'F','o','n','t','s','\0'};
371 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
372 'W','i','n','d','o','w','s',' ','N','T','\\',
373 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
374 'F','o','n','t','s','\0'};
376 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
377 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
378 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
379 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
381 static const WCHAR
* const SystemFontValues
[4] = {
388 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
389 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
391 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
392 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
393 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
394 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
395 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
396 'E','u','r','o','p','e','a','n','\0'};
397 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
398 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
399 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
400 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
401 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
402 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
403 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
404 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
405 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
406 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
407 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
408 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
410 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
420 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
428 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
437 typedef struct tagFontSubst
{
453 static struct list mappings_list
= LIST_INIT( mappings_list
);
455 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
457 static CRITICAL_SECTION freetype_cs
;
458 static CRITICAL_SECTION_DEBUG critsect_debug
=
461 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
462 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
464 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
466 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
468 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
469 static BOOL use_default_fallback
= FALSE
;
471 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
473 /****************************************
474 * Notes on .fon files
476 * The fonts System, FixedSys and Terminal are special. There are typically multiple
477 * versions installed for different resolutions and codepages. Windows stores which one to use
478 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
480 * FIXEDFON.FON FixedSys
482 * OEMFONT.FON Terminal
483 * LogPixels Current dpi set by the display control panel applet
484 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
485 * also has a LogPixels value that appears to mirror this)
487 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
488 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
489 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
490 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
491 * so that makes sense.
493 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
494 * to be mapped into the registry on Windows 2000 at least).
497 * ega80woa.fon=ega80850.fon
498 * ega40woa.fon=ega40850.fon
499 * cga80woa.fon=cga80850.fon
500 * cga40woa.fon=cga40850.fon
503 /* These are all structures needed for the GSUB table */
505 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
506 #define TATEGAKI_LOWER_BOUND 0x02F1
522 GSUB_ScriptRecord ScriptRecord
[1];
528 } GSUB_LangSysRecord
;
533 GSUB_LangSysRecord LangSysRecord
[1];
537 WORD LookupOrder
; /* Reserved */
538 WORD ReqFeatureIndex
;
540 WORD FeatureIndex
[1];
546 } GSUB_FeatureRecord
;
550 GSUB_FeatureRecord FeatureRecord
[1];
554 WORD FeatureParams
; /* Reserved */
556 WORD LookupListIndex
[1];
575 } GSUB_CoverageFormat1
;
580 WORD StartCoverageIndex
;
586 GSUB_RangeRecord RangeRecord
[1];
587 } GSUB_CoverageFormat2
;
590 WORD SubstFormat
; /* = 1 */
593 } GSUB_SingleSubstFormat1
;
596 WORD SubstFormat
; /* = 2 */
600 }GSUB_SingleSubstFormat2
;
602 #ifdef HAVE_CARBON_CARBON_H
603 static char *find_cache_dir(void)
607 static char cached_path
[MAX_PATH
];
608 static const char *wine
= "/Wine", *fonts
= "/Fonts";
610 if(*cached_path
) return cached_path
;
612 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
615 WARN("can't create cached data folder\n");
618 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
621 WARN("can't create cached data path\n");
625 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
627 ERR("Could not create full path\n");
631 strcat(cached_path
, wine
);
633 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
635 WARN("Couldn't mkdir %s\n", cached_path
);
639 strcat(cached_path
, fonts
);
640 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
642 WARN("Couldn't mkdir %s\n", cached_path
);
649 /******************************************************************
652 * Extracts individual TrueType font files from a Mac suitcase font
653 * and saves them into the user's caches directory (see
655 * Returns a NULL terminated array of filenames.
657 * We do this because they are apps that try to read ttf files
658 * themselves and they don't like Mac suitcase files.
660 static char **expand_mac_font(const char *path
)
667 const char *filename
;
671 unsigned int size
, max_size
;
674 TRACE("path %s\n", path
);
676 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
679 WARN("failed to get ref\n");
683 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
686 TRACE("no data fork, so trying resource fork\n");
687 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
690 TRACE("unable to open resource fork\n");
697 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
700 CloseResFile(res_ref
);
704 out_dir
= find_cache_dir();
706 filename
= strrchr(path
, '/');
707 if(!filename
) filename
= path
;
710 /* output filename has the form out_dir/filename_%04x.ttf */
711 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
718 unsigned short *num_faces_ptr
, num_faces
, face
;
721 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
723 fond
= Get1IndResource(fond_res
, idx
);
725 TRACE("got fond resource %d\n", idx
);
728 fam_rec
= *(FamRec
**)fond
;
729 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
730 num_faces
= GET_BE_WORD(*num_faces_ptr
);
732 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
733 TRACE("num faces %04x\n", num_faces
);
734 for(face
= 0; face
< num_faces
; face
++, assoc
++)
737 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
738 unsigned short size
, font_id
;
741 size
= GET_BE_WORD(assoc
->fontSize
);
742 font_id
= GET_BE_WORD(assoc
->fontID
);
745 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
749 TRACE("trying to load sfnt id %04x\n", font_id
);
750 sfnt
= GetResource(sfnt_res
, font_id
);
753 TRACE("can't get sfnt resource %04x\n", font_id
);
757 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
762 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
764 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
765 if(fd
!= -1 || errno
== EEXIST
)
769 unsigned char *sfnt_data
;
772 sfnt_data
= *(unsigned char**)sfnt
;
773 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
777 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
780 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
782 ret
.array
[ret
.size
++] = output
;
786 WARN("unable to create %s\n", output
);
787 HeapFree(GetProcessHeap(), 0, output
);
790 ReleaseResource(sfnt
);
793 ReleaseResource(fond
);
796 CloseResFile(res_ref
);
801 #endif /* HAVE_CARBON_CARBON_H */
803 static inline BOOL
is_win9x(void)
805 return GetVersion() & 0x80000000;
808 This function builds an FT_Fixed from a float. It puts the integer part
809 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
810 It fails if the integer part of the float number is greater than SHORT_MAX.
812 static inline FT_Fixed
FT_FixedFromFloat(float f
)
815 unsigned short fract
= (f
- value
) * 0xFFFF;
816 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
820 This function builds an FT_Fixed from a FIXED. It simply put f.value
821 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
823 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
825 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
829 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
834 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
835 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
837 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
838 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
840 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
842 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
844 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
848 file
= strrchr(face
->file
, '/');
853 if(!strcasecmp(file
, file_nameA
))
855 HeapFree(GetProcessHeap(), 0, file_nameA
);
860 HeapFree(GetProcessHeap(), 0, file_nameA
);
864 static Family
*find_family_from_name(const WCHAR
*name
)
868 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
870 if(!strcmpiW(family
->FamilyName
, name
))
877 static void DumpSubstList(void)
881 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
883 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
884 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
885 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
887 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
888 debugstr_w(psub
->to
.name
));
893 static LPWSTR
strdupW(LPCWSTR p
)
896 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
897 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
902 static LPSTR
strdupA(LPCSTR p
)
905 DWORD len
= (strlen(p
) + 1);
906 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
911 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
916 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
918 if(!strcmpiW(element
->from
.name
, from_name
) &&
919 (element
->from
.charset
== from_charset
||
920 element
->from
.charset
== -1))
927 #define ADD_FONT_SUBST_FORCE 1
929 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
931 FontSubst
*from_exist
, *to_exist
;
933 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
935 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
937 list_remove(&from_exist
->entry
);
938 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
939 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
940 HeapFree(GetProcessHeap(), 0, from_exist
);
946 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
950 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
951 subst
->to
.name
= strdupW(to_exist
->to
.name
);
954 list_add_tail(subst_list
, &subst
->entry
);
959 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
960 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
961 HeapFree(GetProcessHeap(), 0, subst
);
965 static void split_subst_info(NameCs
*nc
, LPSTR str
)
967 CHAR
*p
= strrchr(str
, ',');
972 nc
->charset
= strtol(p
+1, NULL
, 10);
975 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
976 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
977 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
980 static void LoadSubstList(void)
984 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
988 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
989 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
990 &hkey
) == ERROR_SUCCESS
) {
992 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
993 &valuelen
, &datalen
, NULL
, NULL
);
995 valuelen
++; /* returned value doesn't include room for '\0' */
996 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
997 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1001 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1002 &dlen
) == ERROR_SUCCESS
) {
1003 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1005 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1006 split_subst_info(&psub
->from
, value
);
1007 split_subst_info(&psub
->to
, data
);
1009 /* Win 2000 doesn't allow mapping between different charsets
1010 or mapping of DEFAULT_CHARSET */
1011 if((psub
->to
.charset
!= psub
->from
.charset
) ||
1012 psub
->to
.charset
== DEFAULT_CHARSET
) {
1013 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1014 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1015 HeapFree(GetProcessHeap(), 0, psub
);
1017 add_font_subst(&font_subst_list
, psub
, 0);
1019 /* reset dlen and vlen */
1023 HeapFree(GetProcessHeap(), 0, data
);
1024 HeapFree(GetProcessHeap(), 0, value
);
1029 static WCHAR
*get_familyname(FT_Face ft_face
)
1031 WCHAR
*family
= NULL
;
1033 FT_UInt num_names
, name_index
, i
;
1035 if(FT_IS_SFNT(ft_face
))
1037 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1039 for(name_index
= 0; name_index
< num_names
; name_index
++)
1041 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1043 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
1044 (name
.language_id
== GetUserDefaultLCID()) &&
1045 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
1046 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
1048 /* String is not nul terminated and string_len is a byte length. */
1049 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1050 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1052 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1053 family
[i
] = GET_BE_WORD(*tmp
);
1057 TRACE("Got localised name %s\n", debugstr_w(family
));
1068 /*****************************************************************
1071 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1072 * of FreeType that don't export this function.
1075 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1080 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1081 if(pFT_Load_Sfnt_Table
)
1083 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1085 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1086 else /* Do it the hard way */
1088 TT_Face tt_face
= (TT_Face
) ft_face
;
1089 SFNT_Interface
*sfnt
;
1090 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1093 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1097 /* A field was added in the middle of the structure in 2.1.x */
1098 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1100 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1108 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1109 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1110 "Please upgrade your freetype library.\n");
1113 err
= FT_Err_Unimplemented_Feature
;
1119 static inline int TestStyles(DWORD flags
, DWORD styles
)
1121 return (flags
& styles
) == styles
;
1124 static int StyleOrdering(Face
*face
)
1126 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1128 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1130 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1132 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1135 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1136 debugstr_w(face
->family
->FamilyName
),
1137 debugstr_w(face
->StyleName
),
1143 /* Add a style of face to a font family using an ordering of the list such
1144 that regular fonts come before bold and italic, and single styles come
1145 before compound styles. */
1146 static void AddFaceToFamily(Face
*face
, Family
*family
)
1150 LIST_FOR_EACH( entry
, &family
->faces
)
1152 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1153 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1155 list_add_before( entry
, &face
->entry
);
1158 #define ADDFONT_EXTERNAL_FONT 0x01
1159 #define ADDFONT_FORCE_BITMAP 0x02
1160 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1164 TT_Header
*pHeader
= NULL
;
1165 WCHAR
*english_family
, *localised_family
, *StyleW
;
1169 struct list
*family_elem_ptr
, *face_elem_ptr
;
1171 FT_Long face_index
= 0, num_faces
;
1172 #ifdef HAVE_FREETYPE_FTWINFNT_H
1173 FT_WinFNT_HeaderRec winfnt_header
;
1175 int i
, bitmap_num
, internal_leading
;
1178 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1179 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1181 #ifdef HAVE_CARBON_CARBON_H
1182 if(file
&& !fake_family
)
1184 char **mac_list
= expand_mac_font(file
);
1187 BOOL had_one
= FALSE
;
1189 for(cursor
= mac_list
; *cursor
; cursor
++)
1192 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1193 HeapFree(GetProcessHeap(), 0, *cursor
);
1195 HeapFree(GetProcessHeap(), 0, mac_list
);
1200 #endif /* HAVE_CARBON_CARBON_H */
1203 char *family_name
= fake_family
;
1207 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1208 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1211 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1212 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1216 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1220 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*/
1221 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1222 pFT_Done_Face(ft_face
);
1226 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1227 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1228 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1229 pFT_Done_Face(ft_face
);
1233 if(FT_IS_SFNT(ft_face
))
1235 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1236 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1237 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1239 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1240 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1241 pFT_Done_Face(ft_face
);
1245 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1246 we don't want to load these. */
1247 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1251 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1253 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1254 pFT_Done_Face(ft_face
);
1260 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1261 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1262 pFT_Done_Face(ft_face
);
1266 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1268 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1269 pFT_Done_Face(ft_face
);
1275 localised_family
= get_familyname(ft_face
);
1276 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1278 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1279 HeapFree(GetProcessHeap(), 0, localised_family
);
1280 num_faces
= ft_face
->num_faces
;
1281 pFT_Done_Face(ft_face
);
1284 HeapFree(GetProcessHeap(), 0, localised_family
);
1288 family_name
= ft_face
->family_name
;
1292 My_FT_Bitmap_Size
*size
= NULL
;
1295 if(!FT_IS_SCALABLE(ft_face
))
1296 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1298 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1299 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1300 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1302 localised_family
= NULL
;
1304 localised_family
= get_familyname(ft_face
);
1305 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1306 HeapFree(GetProcessHeap(), 0, localised_family
);
1307 localised_family
= NULL
;
1312 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1313 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1314 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1319 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1320 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1321 list_init(&family
->faces
);
1322 list_add_tail(&font_list
, &family
->entry
);
1324 if(localised_family
) {
1325 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1326 subst
->from
.name
= strdupW(english_family
);
1327 subst
->from
.charset
= -1;
1328 subst
->to
.name
= strdupW(localised_family
);
1329 subst
->to
.charset
= -1;
1330 add_font_subst(&font_subst_list
, subst
, 0);
1333 HeapFree(GetProcessHeap(), 0, localised_family
);
1334 HeapFree(GetProcessHeap(), 0, english_family
);
1336 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1337 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1338 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1340 internal_leading
= 0;
1341 memset(&fs
, 0, sizeof(fs
));
1343 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1345 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1346 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1347 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1348 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1349 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1350 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1351 if(pOS2
->version
== 0) {
1354 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1355 fs
.fsCsb
[0] |= FS_LATIN1
;
1357 fs
.fsCsb
[0] |= FS_SYMBOL
;
1360 #ifdef HAVE_FREETYPE_FTWINFNT_H
1361 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1363 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1364 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1365 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1367 internal_leading
= winfnt_header
.internal_leading
;
1371 face_elem_ptr
= list_head(&family
->faces
);
1372 while(face_elem_ptr
) {
1373 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1374 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1375 if(!strcmpW(face
->StyleName
, StyleW
) &&
1376 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1377 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1378 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1379 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1382 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1383 HeapFree(GetProcessHeap(), 0, StyleW
);
1384 pFT_Done_Face(ft_face
);
1387 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1388 TRACE("Original font is newer so skipping this one\n");
1389 HeapFree(GetProcessHeap(), 0, StyleW
);
1390 pFT_Done_Face(ft_face
);
1393 TRACE("Replacing original with this one\n");
1394 list_remove(&face
->entry
);
1395 HeapFree(GetProcessHeap(), 0, face
->file
);
1396 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1397 HeapFree(GetProcessHeap(), 0, face
);
1402 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1403 face
->cached_enum_data
= NULL
;
1404 face
->StyleName
= StyleW
;
1407 face
->file
= strdupA(file
);
1408 face
->font_data_ptr
= NULL
;
1409 face
->font_data_size
= 0;
1414 face
->font_data_ptr
= font_data_ptr
;
1415 face
->font_data_size
= font_data_size
;
1417 face
->face_index
= face_index
;
1419 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1420 face
->ntmFlags
|= NTM_ITALIC
;
1421 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1422 face
->ntmFlags
|= NTM_BOLD
;
1423 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1424 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1425 face
->family
= family
;
1426 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1428 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1430 if(FT_IS_SCALABLE(ft_face
)) {
1431 memset(&face
->size
, 0, sizeof(face
->size
));
1432 face
->scalable
= TRUE
;
1434 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1435 size
->height
, size
->width
, size
->size
>> 6,
1436 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1437 face
->size
.height
= size
->height
;
1438 face
->size
.width
= size
->width
;
1439 face
->size
.size
= size
->size
;
1440 face
->size
.x_ppem
= size
->x_ppem
;
1441 face
->size
.y_ppem
= size
->y_ppem
;
1442 face
->size
.internal_leading
= internal_leading
;
1443 face
->scalable
= FALSE
;
1446 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1448 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1450 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1451 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1454 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1455 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1456 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1457 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1460 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1461 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1462 switch(ft_face
->charmaps
[i
]->encoding
) {
1463 case FT_ENCODING_UNICODE
:
1464 case FT_ENCODING_APPLE_ROMAN
:
1465 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1467 case FT_ENCODING_MS_SYMBOL
:
1468 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1476 if (!(face
->fs
.fsCsb
[0] & FS_SYMBOL
))
1477 have_installed_roman_font
= TRUE
;
1479 AddFaceToFamily(face
, family
);
1481 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1483 num_faces
= ft_face
->num_faces
;
1484 pFT_Done_Face(ft_face
);
1485 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1486 debugstr_w(StyleW
));
1487 } while(num_faces
> ++face_index
);
1491 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1493 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1496 static void DumpFontList(void)
1500 struct list
*family_elem_ptr
, *face_elem_ptr
;
1502 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1503 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1504 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1505 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1506 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1507 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1509 TRACE(" %d", face
->size
.height
);
1516 /***********************************************************
1517 * The replacement list is a way to map an entire font
1518 * family onto another family. For example adding
1520 * [HKCU\Software\Wine\Fonts\Replacements]
1521 * "Wingdings"="Winedings"
1523 * would enumerate the Winedings font both as Winedings and
1524 * Wingdings. However if a real Wingdings font is present the
1525 * replacement does not take place.
1528 static void LoadReplaceList(void)
1531 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1536 struct list
*family_elem_ptr
, *face_elem_ptr
;
1539 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1540 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1542 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1543 &valuelen
, &datalen
, NULL
, NULL
);
1545 valuelen
++; /* returned value doesn't include room for '\0' */
1546 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1547 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1551 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1552 &dlen
) == ERROR_SUCCESS
) {
1553 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1554 /* "NewName"="Oldname" */
1555 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1557 /* Find the old family and hence all of the font files
1559 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1560 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1561 if(!strcmpiW(family
->FamilyName
, data
)) {
1562 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1563 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1564 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1565 debugstr_w(face
->StyleName
), familyA
);
1566 /* Now add a new entry with the new family name */
1567 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1572 /* reset dlen and vlen */
1576 HeapFree(GetProcessHeap(), 0, data
);
1577 HeapFree(GetProcessHeap(), 0, value
);
1582 /*************************************************************
1585 static BOOL
init_system_links(void)
1587 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1588 'W','i','n','d','o','w','s',' ','N','T','\\',
1589 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1590 'S','y','s','t','e','m','L','i','n','k',0};
1593 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1594 WCHAR
*value
, *data
;
1595 WCHAR
*entry
, *next
;
1596 SYSTEM_LINKS
*font_link
, *system_font_link
;
1597 CHILD_FONT
*child_font
;
1598 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1599 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1600 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1606 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1608 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1609 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1610 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1611 val_len
= max_val
+ 1;
1612 data_len
= max_data
;
1614 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1616 TRACE("%s:\n", debugstr_w(value
));
1618 memset(&fs
, 0, sizeof(fs
));
1619 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1620 psub
= get_font_subst(&font_subst_list
, value
, -1);
1621 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1622 list_init(&font_link
->links
);
1623 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1626 CHILD_FONT
*child_font
;
1628 TRACE("\t%s\n", debugstr_w(entry
));
1630 next
= entry
+ strlenW(entry
) + 1;
1632 face_name
= strchrW(entry
, ',');
1636 while(isspaceW(*face_name
))
1639 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1641 face_name
= psub
->to
.name
;
1643 face
= find_face_from_filename(entry
, face_name
);
1646 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1650 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1651 child_font
->face
= face
;
1652 child_font
->font
= NULL
;
1653 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1654 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1655 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1656 list_add_tail(&font_link
->links
, &child_font
->entry
);
1658 family
= find_family_from_name(font_link
->font_name
);
1661 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1663 face
->fs_links
= fs
;
1666 list_add_tail(&system_links
, &font_link
->entry
);
1667 val_len
= max_val
+ 1;
1668 data_len
= max_data
;
1671 HeapFree(GetProcessHeap(), 0, value
);
1672 HeapFree(GetProcessHeap(), 0, data
);
1676 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1679 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1680 system_font_link
->font_name
= strdupW(System
);
1681 list_init(&system_font_link
->links
);
1683 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1686 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1687 child_font
->face
= face
;
1688 child_font
->font
= NULL
;
1689 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1690 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1692 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1694 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1696 CHILD_FONT
*font_link_entry
;
1697 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1699 CHILD_FONT
*new_child
;
1700 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1701 new_child
->face
= font_link_entry
->face
;
1702 new_child
->font
= NULL
;
1703 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1708 list_add_tail(&system_links
, &system_font_link
->entry
);
1712 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1715 struct dirent
*dent
;
1716 char path
[MAX_PATH
];
1718 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1720 dir
= opendir(dirname
);
1722 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1725 while((dent
= readdir(dir
)) != NULL
) {
1726 struct stat statbuf
;
1728 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1731 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1733 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1735 if(stat(path
, &statbuf
) == -1)
1737 WARN("Can't stat %s\n", debugstr_a(path
));
1740 if(S_ISDIR(statbuf
.st_mode
))
1741 ReadFontDir(path
, external_fonts
);
1743 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1749 static void load_fontconfig_fonts(void)
1751 #ifdef SONAME_LIBFONTCONFIG
1752 void *fc_handle
= NULL
;
1761 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1763 TRACE("Wine cannot find the fontconfig library (%s).\n",
1764 SONAME_LIBFONTCONFIG
);
1767 #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;}
1768 LOAD_FUNCPTR(FcConfigGetCurrent
);
1769 LOAD_FUNCPTR(FcFontList
);
1770 LOAD_FUNCPTR(FcFontSetDestroy
);
1771 LOAD_FUNCPTR(FcInit
);
1772 LOAD_FUNCPTR(FcObjectSetAdd
);
1773 LOAD_FUNCPTR(FcObjectSetCreate
);
1774 LOAD_FUNCPTR(FcObjectSetDestroy
);
1775 LOAD_FUNCPTR(FcPatternCreate
);
1776 LOAD_FUNCPTR(FcPatternDestroy
);
1777 LOAD_FUNCPTR(FcPatternGetBool
);
1778 LOAD_FUNCPTR(FcPatternGetString
);
1781 if(!pFcInit()) return;
1783 config
= pFcConfigGetCurrent();
1784 pat
= pFcPatternCreate();
1785 os
= pFcObjectSetCreate();
1786 pFcObjectSetAdd(os
, FC_FILE
);
1787 pFcObjectSetAdd(os
, FC_SCALABLE
);
1788 fontset
= pFcFontList(config
, pat
, os
);
1789 if(!fontset
) return;
1790 for(i
= 0; i
< fontset
->nfont
; i
++) {
1793 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1795 TRACE("fontconfig: %s\n", file
);
1797 /* We're just interested in OT/TT fonts for now, so this hack just
1798 picks up the scalable fonts without extensions .pf[ab] to save time
1799 loading every other font */
1801 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1803 TRACE("not scalable\n");
1807 len
= strlen( file
);
1808 if(len
< 4) continue;
1809 ext
= &file
[ len
- 3 ];
1810 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1811 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1813 pFcFontSetDestroy(fontset
);
1814 pFcObjectSetDestroy(os
);
1815 pFcPatternDestroy(pat
);
1821 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1824 const char *data_dir
= wine_get_data_dir();
1826 if (!data_dir
) data_dir
= wine_get_build_dir();
1833 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1835 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1837 strcpy(unix_name
, data_dir
);
1838 strcat(unix_name
, "/fonts/");
1840 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1842 EnterCriticalSection( &freetype_cs
);
1843 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1844 LeaveCriticalSection( &freetype_cs
);
1845 HeapFree(GetProcessHeap(), 0, unix_name
);
1850 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1852 static const WCHAR slashW
[] = {'\\','\0'};
1854 WCHAR windowsdir
[MAX_PATH
];
1857 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1858 strcatW(windowsdir
, fontsW
);
1859 strcatW(windowsdir
, slashW
);
1860 strcatW(windowsdir
, file
);
1861 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1862 EnterCriticalSection( &freetype_cs
);
1863 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1864 LeaveCriticalSection( &freetype_cs
);
1865 HeapFree(GetProcessHeap(), 0, unixname
);
1870 static void load_system_fonts(void)
1873 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1874 const WCHAR
* const *value
;
1876 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1879 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1880 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1881 strcatW(windowsdir
, fontsW
);
1882 for(value
= SystemFontValues
; *value
; value
++) {
1883 dlen
= sizeof(data
);
1884 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1888 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1889 if((unixname
= wine_get_unix_file_name(pathW
))) {
1890 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1891 HeapFree(GetProcessHeap(), 0, unixname
);
1894 load_font_from_data_dir(data
);
1901 /*************************************************************
1903 * This adds registry entries for any externally loaded fonts
1904 * (fonts from fontconfig or FontDirs). It also deletes entries
1905 * of no longer existing fonts.
1908 static void update_reg_entries(void)
1910 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1915 struct list
*family_elem_ptr
, *face_elem_ptr
;
1917 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1918 static const WCHAR spaceW
[] = {' ', '\0'};
1921 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1922 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1923 ERR("Can't create Windows font reg key\n");
1927 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1928 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1929 ERR("Can't create Windows font reg key\n");
1933 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1934 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
1935 ERR("Can't create external font reg key\n");
1939 /* enumerate the fonts and add external ones to the two keys */
1941 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1942 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1943 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1944 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1945 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1946 if(!face
->external
) continue;
1948 if(strcmpiW(face
->StyleName
, RegularW
))
1949 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1950 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1951 strcpyW(valueW
, family
->FamilyName
);
1952 if(len
!= len_fam
) {
1953 strcatW(valueW
, spaceW
);
1954 strcatW(valueW
, face
->StyleName
);
1956 strcatW(valueW
, TrueType
);
1958 file
= wine_get_dos_file_name(face
->file
);
1960 len
= strlenW(file
) + 1;
1963 if((path
= strrchr(face
->file
, '/')) == NULL
)
1967 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1969 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1970 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1972 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1973 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1974 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1976 HeapFree(GetProcessHeap(), 0, file
);
1977 HeapFree(GetProcessHeap(), 0, valueW
);
1981 if(external_key
) RegCloseKey(external_key
);
1982 if(win9x_key
) RegCloseKey(win9x_key
);
1983 if(winnt_key
) RegCloseKey(winnt_key
);
1987 static void delete_external_font_keys(void)
1989 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1990 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
1994 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1995 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1996 ERR("Can't create Windows font reg key\n");
2000 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2001 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2002 ERR("Can't create Windows font reg key\n");
2006 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2007 ERR("Can't create external font reg key\n");
2011 /* Delete all external fonts added last time */
2013 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2014 &valuelen
, &datalen
, NULL
, NULL
);
2015 valuelen
++; /* returned value doesn't include room for '\0' */
2016 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2017 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2019 dlen
= datalen
* sizeof(WCHAR
);
2022 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2023 &dlen
) == ERROR_SUCCESS
) {
2025 RegDeleteValueW(winnt_key
, valueW
);
2026 RegDeleteValueW(win9x_key
, valueW
);
2027 /* reset dlen and vlen */
2031 HeapFree(GetProcessHeap(), 0, data
);
2032 HeapFree(GetProcessHeap(), 0, valueW
);
2034 /* Delete the old external fonts key */
2035 RegCloseKey(external_key
);
2036 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2039 if(win9x_key
) RegCloseKey(win9x_key
);
2040 if(winnt_key
) RegCloseKey(winnt_key
);
2043 /*************************************************************
2044 * WineEngAddFontResourceEx
2047 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2050 if (ft_handle
) /* do it only if we have freetype up and running */
2055 FIXME("Ignoring flags %x\n", flags
);
2057 if((unixname
= wine_get_unix_file_name(file
)))
2059 EnterCriticalSection( &freetype_cs
);
2060 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2061 LeaveCriticalSection( &freetype_cs
);
2062 HeapFree(GetProcessHeap(), 0, unixname
);
2064 if (!ret
&& !strchrW(file
, '\\')) {
2065 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2066 ret
= load_font_from_winfonts_dir(file
);
2068 /* Try in datadir/fonts (or builddir/fonts),
2069 * needed for Magic the Gathering Online
2071 ret
= load_font_from_data_dir(file
);
2078 /*************************************************************
2079 * WineEngAddFontMemResourceEx
2082 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2084 if (ft_handle
) /* do it only if we have freetype up and running */
2086 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2088 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2089 memcpy(pFontCopy
, pbFont
, cbFont
);
2091 EnterCriticalSection( &freetype_cs
);
2092 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2093 LeaveCriticalSection( &freetype_cs
);
2097 TRACE("AddFontToList failed\n");
2098 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2101 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2102 * For now return something unique but quite random
2104 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2105 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2112 /*************************************************************
2113 * WineEngRemoveFontResourceEx
2116 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2122 static const struct nls_update_font_list
2124 UINT ansi_cp
, oem_cp
;
2125 const char *oem
, *fixed
, *system
;
2126 const char *courier
, *serif
, *small
, *sserif
;
2127 /* these are for font substitute */
2128 const char *shelldlg
, *tmsrmn
;
2129 } nls_update_font_list
[] =
2131 /* Latin 1 (United States) */
2132 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2133 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2134 "Tahoma","Times New Roman",
2136 /* Latin 1 (Multilingual) */
2137 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2138 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2139 "Tahoma","Times New Roman", /* FIXME unverified */
2141 /* Eastern Europe */
2142 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2143 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2144 "Tahoma","Times New Roman", /* FIXME unverified */
2147 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2148 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2149 "Tahoma","Times New Roman", /* FIXME unverified */
2152 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2153 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2154 "Tahoma","Times New Roman", /* FIXME unverified */
2157 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2158 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2159 "Tahoma","Times New Roman", /* FIXME unverified */
2162 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2163 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2164 "Tahoma","Times New Roman", /* FIXME unverified */
2167 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2168 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2169 "Tahoma","Times New Roman", /* FIXME unverified */
2172 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2173 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2174 "Tahoma","Times New Roman", /* FIXME unverified */
2177 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2178 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2179 "Tahoma","Times New Roman", /* FIXME unverified */
2182 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2183 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2184 "Tahoma","Times New Roman", /* FIXME unverified */
2187 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2188 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2189 "MS UI Gothic","MS Serif",
2191 /* Chinese Simplified */
2192 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2193 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2194 "Tahoma", "Times New Roman", /* FIXME unverified */
2197 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2198 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2201 /* Chinese Traditional */
2202 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2203 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2204 "PMingLiU", "MingLiU",
2208 static inline HKEY
create_fonts_NT_registry_key(void)
2212 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2213 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2217 static inline HKEY
create_fonts_9x_registry_key(void)
2221 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2222 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2226 static inline HKEY
create_config_fonts_registry_key(void)
2230 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2231 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2235 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2237 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2238 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2239 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2240 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2243 static void update_font_info(void)
2245 char buf
[40], cpbuf
[40];
2248 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2250 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2253 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2254 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2255 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2256 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2257 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2259 /* Setup Default_Fallback usage */
2261 use_default_fallback
= TRUE
;
2264 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2266 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2271 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2273 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2275 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2278 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2280 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2281 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2285 hkey
= create_config_fonts_registry_key();
2286 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2287 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2288 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2291 hkey
= create_fonts_NT_registry_key();
2292 add_font_list(hkey
, &nls_update_font_list
[i
]);
2295 hkey
= create_fonts_9x_registry_key();
2296 add_font_list(hkey
, &nls_update_font_list
[i
]);
2299 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2301 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2302 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2303 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2304 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2310 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2314 static BOOL
init_freetype(void)
2316 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2319 "Wine cannot find the FreeType font library. To enable Wine to\n"
2320 "use TrueType fonts please install a version of FreeType greater than\n"
2321 "or equal to 2.0.5.\n"
2322 "http://www.freetype.org\n");
2326 #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;}
2328 LOAD_FUNCPTR(FT_Vector_Unit
)
2329 LOAD_FUNCPTR(FT_Done_Face
)
2330 LOAD_FUNCPTR(FT_Get_Char_Index
)
2331 LOAD_FUNCPTR(FT_Get_Module
)
2332 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2333 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2334 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2335 LOAD_FUNCPTR(FT_Init_FreeType
)
2336 LOAD_FUNCPTR(FT_Load_Glyph
)
2337 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2338 LOAD_FUNCPTR(FT_MulFix
)
2339 LOAD_FUNCPTR(FT_New_Face
)
2340 LOAD_FUNCPTR(FT_New_Memory_Face
)
2341 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2342 LOAD_FUNCPTR(FT_Outline_Transform
)
2343 LOAD_FUNCPTR(FT_Outline_Translate
)
2344 LOAD_FUNCPTR(FT_Select_Charmap
)
2345 LOAD_FUNCPTR(FT_Set_Charmap
)
2346 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2347 LOAD_FUNCPTR(FT_Vector_Transform
)
2350 /* Don't warn if these ones are missing */
2351 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2352 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2353 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2354 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2355 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2356 #ifdef HAVE_FREETYPE_FTWINFNT_H
2357 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2359 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2360 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2361 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2362 <= 2.0.3 has FT_Sqrt64 */
2366 if(pFT_Init_FreeType(&library
) != 0) {
2367 ERR("Can't init FreeType library\n");
2368 wine_dlclose(ft_handle
, NULL
, 0);
2372 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2373 if (pFT_Library_Version
)
2374 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2376 if (FT_Version
.major
<=0)
2382 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2383 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2384 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2385 ((FT_Version
.patch
) & 0x0000ff);
2391 "Wine cannot find certain functions that it needs inside the FreeType\n"
2392 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2393 "FreeType to at least version 2.0.5.\n"
2394 "http://www.freetype.org\n");
2395 wine_dlclose(ft_handle
, NULL
, 0);
2400 /*************************************************************
2403 * Initialize FreeType library and create a list of available faces
2405 BOOL
WineEngInit(void)
2407 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2408 static const WCHAR pathW
[] = {'P','a','t','h',0};
2410 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2412 WCHAR windowsdir
[MAX_PATH
];
2415 const char *data_dir
;
2419 /* update locale dependent font info in registry */
2422 if(!init_freetype()) return FALSE
;
2424 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2425 ERR("Failed to create font mutex\n");
2428 WaitForSingleObject(font_mutex
, INFINITE
);
2430 delete_external_font_keys();
2432 /* load the system bitmap fonts */
2433 load_system_fonts();
2435 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2436 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2437 strcatW(windowsdir
, fontsW
);
2438 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2440 ReadFontDir(unixname
, FALSE
);
2441 HeapFree(GetProcessHeap(), 0, unixname
);
2444 /* load the system truetype fonts */
2445 data_dir
= wine_get_data_dir();
2446 if (!data_dir
) data_dir
= wine_get_build_dir();
2447 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2448 strcpy(unixname
, data_dir
);
2449 strcat(unixname
, "/fonts/");
2450 ReadFontDir(unixname
, TRUE
);
2451 HeapFree(GetProcessHeap(), 0, unixname
);
2454 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2455 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2456 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2458 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2459 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2460 &hkey
) == ERROR_SUCCESS
) {
2462 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2463 &valuelen
, &datalen
, NULL
, NULL
);
2465 valuelen
++; /* returned value doesn't include room for '\0' */
2466 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2467 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2470 dlen
= datalen
* sizeof(WCHAR
);
2472 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2473 &dlen
) == ERROR_SUCCESS
) {
2474 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2476 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2478 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2479 HeapFree(GetProcessHeap(), 0, unixname
);
2482 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2484 WCHAR pathW
[MAX_PATH
];
2485 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2488 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2489 if((unixname
= wine_get_unix_file_name(pathW
)))
2491 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2492 HeapFree(GetProcessHeap(), 0, unixname
);
2495 load_font_from_data_dir(data
);
2497 /* reset dlen and vlen */
2502 HeapFree(GetProcessHeap(), 0, data
);
2503 HeapFree(GetProcessHeap(), 0, valueW
);
2507 load_fontconfig_fonts();
2509 /* then look in any directories that we've specified in the config file */
2510 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2511 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2517 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2519 len
+= sizeof(WCHAR
);
2520 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2521 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2523 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2524 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2525 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2526 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2530 LPSTR next
= strchr( ptr
, ':' );
2531 if (next
) *next
++ = 0;
2532 ReadFontDir( ptr
, TRUE
);
2535 HeapFree( GetProcessHeap(), 0, valueA
);
2537 HeapFree( GetProcessHeap(), 0, valueW
);
2546 update_reg_entries();
2548 init_system_links();
2550 ReleaseMutex(font_mutex
);
2555 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2558 TT_HoriHeader
*pHori
;
2562 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2563 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2565 if(height
== 0) height
= 16;
2567 /* Calc. height of EM square:
2569 * For +ve lfHeight we have
2570 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2571 * Re-arranging gives:
2572 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2574 * For -ve lfHeight we have
2576 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2577 * with il = winAscent + winDescent - units_per_em]
2582 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2583 ppem
= ft_face
->units_per_EM
* height
/
2584 (pHori
->Ascender
- pHori
->Descender
);
2586 ppem
= ft_face
->units_per_EM
* height
/
2587 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2595 static struct font_mapping
*map_font_file( const char *name
)
2597 struct font_mapping
*mapping
;
2601 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2602 if (fstat( fd
, &st
) == -1) goto error
;
2604 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2606 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2608 mapping
->refcount
++;
2613 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2616 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2619 if (mapping
->data
== MAP_FAILED
)
2621 HeapFree( GetProcessHeap(), 0, mapping
);
2624 mapping
->refcount
= 1;
2625 mapping
->dev
= st
.st_dev
;
2626 mapping
->ino
= st
.st_ino
;
2627 mapping
->size
= st
.st_size
;
2628 list_add_tail( &mappings_list
, &mapping
->entry
);
2636 static void unmap_font_file( struct font_mapping
*mapping
)
2638 if (!--mapping
->refcount
)
2640 list_remove( &mapping
->entry
);
2641 munmap( mapping
->data
, mapping
->size
);
2642 HeapFree( GetProcessHeap(), 0, mapping
);
2646 static LONG
load_VDMX(GdiFont
*, LONG
);
2648 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2655 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2659 if (!(font
->mapping
= map_font_file( face
->file
)))
2661 WARN("failed to map %s\n", debugstr_a(face
->file
));
2664 data_ptr
= font
->mapping
->data
;
2665 data_size
= font
->mapping
->size
;
2669 data_ptr
= face
->font_data_ptr
;
2670 data_size
= face
->font_data_size
;
2673 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2675 ERR("FT_New_Face rets %d\n", err
);
2679 /* set it here, as load_VDMX needs it */
2680 font
->ft_face
= ft_face
;
2682 if(FT_IS_SCALABLE(ft_face
)) {
2683 /* load the VDMX table if we have one */
2684 font
->ppem
= load_VDMX(font
, height
);
2686 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2688 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2689 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2691 font
->ppem
= height
;
2692 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2693 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2699 static int get_nearest_charset(Face
*face
, int *cp
)
2701 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2702 a single face with the requested charset. The idea is to check if
2703 the selected font supports the current ANSI codepage, if it does
2704 return the corresponding charset, else return the first charset */
2707 int acp
= GetACP(), i
;
2711 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2712 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2713 return csi
.ciCharset
;
2715 for(i
= 0; i
< 32; i
++) {
2717 if(face
->fs
.fsCsb
[0] & fs0
) {
2718 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2720 return csi
.ciCharset
;
2723 FIXME("TCI failing on %x\n", fs0
);
2727 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2728 face
->fs
.fsCsb
[0], face
->file
);
2730 return DEFAULT_CHARSET
;
2733 static GdiFont
*alloc_font(void)
2735 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2737 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2738 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2740 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2741 ret
->total_kern_pairs
= (DWORD
)-1;
2742 ret
->kern_pairs
= NULL
;
2743 list_init(&ret
->hfontlist
);
2744 list_init(&ret
->child_fonts
);
2748 static void free_font(GdiFont
*font
)
2750 struct list
*cursor
, *cursor2
;
2753 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2755 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2756 struct list
*first_hfont
;
2757 HFONTLIST
*hfontlist
;
2758 list_remove(cursor
);
2761 first_hfont
= list_head(&child
->font
->hfontlist
);
2762 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2763 DeleteObject(hfontlist
->hfont
);
2764 HeapFree(GetProcessHeap(), 0, hfontlist
);
2765 free_font(child
->font
);
2767 HeapFree(GetProcessHeap(), 0, child
);
2770 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2771 if (font
->mapping
) unmap_font_file( font
->mapping
);
2772 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2773 HeapFree(GetProcessHeap(), 0, font
->potm
);
2774 HeapFree(GetProcessHeap(), 0, font
->name
);
2775 for (i
= 0; i
< font
->gmsize
; i
++)
2776 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2777 HeapFree(GetProcessHeap(), 0, font
->gm
);
2778 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
2779 HeapFree(GetProcessHeap(), 0, font
);
2783 /*************************************************************
2786 * load the vdmx entry for the specified height
2789 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2790 ( ( (FT_ULong)_x4 << 24 ) | \
2791 ( (FT_ULong)_x3 << 16 ) | \
2792 ( (FT_ULong)_x2 << 8 ) | \
2795 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2810 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2814 BYTE devXRatio
, devYRatio
;
2815 USHORT numRecs
, numRatios
;
2816 DWORD result
, offset
= -1;
2820 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2822 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2825 /* FIXME: need the real device aspect ratio */
2829 numRecs
= GET_BE_WORD(hdr
[1]);
2830 numRatios
= GET_BE_WORD(hdr
[2]);
2832 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2833 for(i
= 0; i
< numRatios
; i
++) {
2836 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2837 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2840 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2842 if((ratio
.xRatio
== 0 &&
2843 ratio
.yStartRatio
== 0 &&
2844 ratio
.yEndRatio
== 0) ||
2845 (devXRatio
== ratio
.xRatio
&&
2846 devYRatio
>= ratio
.yStartRatio
&&
2847 devYRatio
<= ratio
.yEndRatio
))
2849 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2850 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2851 offset
= GET_BE_WORD(tmp
);
2857 FIXME("No suitable ratio found\n");
2861 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2863 BYTE startsz
, endsz
;
2866 recs
= GET_BE_WORD(group
.recs
);
2867 startsz
= group
.startsz
;
2868 endsz
= group
.endsz
;
2870 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2872 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2873 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2874 if(result
== GDI_ERROR
) {
2875 FIXME("Failed to retrieve vTable\n");
2880 for(i
= 0; i
< recs
; i
++) {
2881 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2882 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2883 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2885 if(yMax
+ -yMin
== height
) {
2888 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2891 if(yMax
+ -yMin
> height
) {
2894 goto end
; /* failed */
2896 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2897 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2898 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2899 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2905 TRACE("ppem not found for height %d\n", height
);
2909 if(ppem
< startsz
|| ppem
> endsz
)
2912 for(i
= 0; i
< recs
; i
++) {
2914 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2916 if(yPelHeight
> ppem
)
2919 if(yPelHeight
== ppem
) {
2920 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2921 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2922 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2928 HeapFree(GetProcessHeap(), 0, vTable
);
2934 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
2936 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2937 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2938 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2939 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2940 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2943 static void calc_hash(FONT_DESC
*pfd
)
2945 DWORD hash
= 0, *ptr
, two_chars
;
2949 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2951 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2953 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2955 pwc
= (WCHAR
*)&two_chars
;
2957 *pwc
= toupperW(*pwc
);
2959 *pwc
= toupperW(*pwc
);
2963 hash
^= !pfd
->can_use_bitmap
;
2968 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2973 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2976 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2977 fd
.can_use_bitmap
= can_use_bitmap
;
2980 /* try the in-use list */
2981 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2982 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2983 if(!fontcmp(ret
, &fd
)) {
2984 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2985 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2986 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2987 if(hflist
->hfont
== hfont
)
2990 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2991 hflist
->hfont
= hfont
;
2992 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2997 /* then the unused list */
2998 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2999 while(font_elem_ptr
) {
3000 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3001 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3002 if(!fontcmp(ret
, &fd
)) {
3003 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3004 assert(list_empty(&ret
->hfontlist
));
3005 TRACE("Found %p in unused list\n", ret
);
3006 list_remove(&ret
->entry
);
3007 list_add_head(&gdi_font_list
, &ret
->entry
);
3008 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3009 hflist
->hfont
= hfont
;
3010 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3018 /*************************************************************
3019 * create_child_font_list
3021 static BOOL
create_child_font_list(GdiFont
*font
)
3024 SYSTEM_LINKS
*font_link
;
3025 CHILD_FONT
*font_link_entry
, *new_child
;
3027 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3029 if(!strcmpW(font_link
->font_name
, font
->name
))
3031 TRACE("found entry in system list\n");
3032 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3034 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3035 new_child
->face
= font_link_entry
->face
;
3036 new_child
->font
= NULL
;
3037 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3038 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3045 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3046 * Sans Serif. This is how asian windows get default fallbacks for fonts
3048 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3049 font
->charset
!= OEM_CHARSET
&&
3050 strcmpW(font
->name
,szDefaultFallbackLink
) != 0)
3051 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3053 if(!strcmpW(font_link
->font_name
,szDefaultFallbackLink
))
3055 TRACE("found entry in default fallback list\n");
3056 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3058 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3059 new_child
->face
= font_link_entry
->face
;
3060 new_child
->font
= NULL
;
3061 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3062 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3072 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3074 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3076 if (pFT_Set_Charmap
)
3079 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3081 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3083 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3085 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3087 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3088 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3090 switch (ft_face
->charmaps
[i
]->platform_id
)
3093 cmap_def
= ft_face
->charmaps
[i
];
3095 case 0: /* Apple Unicode */
3096 cmap0
= ft_face
->charmaps
[i
];
3098 case 1: /* Macintosh */
3099 cmap1
= ft_face
->charmaps
[i
];
3102 cmap2
= ft_face
->charmaps
[i
];
3104 case 3: /* Microsoft */
3105 cmap3
= ft_face
->charmaps
[i
];
3110 if (cmap3
) /* prefer Microsoft cmap table */
3111 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3113 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3115 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3117 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3119 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3121 return ft_err
== FT_Err_Ok
;
3124 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3127 /*************************************************************
3128 * WineEngCreateFontInstance
3131 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3134 Face
*face
, *best
, *best_bitmap
;
3135 Family
*family
, *last_resort_family
;
3136 struct list
*family_elem_ptr
, *face_elem_ptr
;
3137 INT height
, width
= 0;
3138 unsigned int score
= 0, new_score
;
3139 signed int diff
= 0, newdiff
;
3140 BOOL bd
, it
, can_use_bitmap
;
3145 EnterCriticalSection( &freetype_cs
);
3147 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
3149 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
3150 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3151 if(hflist
->hfont
== hfont
)
3153 LeaveCriticalSection( &freetype_cs
);
3158 if (!GetObjectW( hfont
, sizeof(lf
), &lf
))
3160 LeaveCriticalSection( &freetype_cs
);
3163 lf
.lfWidth
= abs(lf
.lfWidth
);
3165 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3167 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3168 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3169 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3172 /* check the cache first */
3173 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
3174 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3175 LeaveCriticalSection( &freetype_cs
);
3179 TRACE("not in cache\n");
3180 if(list_empty(&font_list
)) /* No fonts installed */
3182 TRACE("No fonts installed\n");
3183 LeaveCriticalSection( &freetype_cs
);
3186 if(!have_installed_roman_font
)
3188 TRACE("No roman font installed\n");
3189 LeaveCriticalSection( &freetype_cs
);
3195 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3196 ret
->font_desc
.lf
= lf
;
3197 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3198 calc_hash(&ret
->font_desc
);
3199 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3200 hflist
->hfont
= hfont
;
3201 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3204 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3205 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3206 original value lfCharSet. Note this is a special case for
3207 Symbol and doesn't happen at least for "Wingdings*" */
3209 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3210 lf
.lfCharSet
= SYMBOL_CHARSET
;
3212 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3213 switch(lf
.lfCharSet
) {
3214 case DEFAULT_CHARSET
:
3215 csi
.fs
.fsCsb
[0] = 0;
3218 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3219 csi
.fs
.fsCsb
[0] = 0;
3225 if(lf
.lfFaceName
[0] != '\0') {
3227 SYSTEM_LINKS
*font_link
;
3228 CHILD_FONT
*font_link_entry
;
3229 LPWSTR FaceName
= lf
.lfFaceName
;
3232 * Check for a leading '@' this signals that the font is being
3233 * requested in tategaki mode (vertical writing substitution) but
3234 * does not affect the fontface that is to be selected.
3236 if (lf
.lfFaceName
[0]=='@')
3237 FaceName
= &lf
.lfFaceName
[1];
3239 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3242 TRACE("substituting %s -> %s\n", debugstr_w(FaceName
),
3243 debugstr_w(psub
->to
.name
));
3244 strcpyW(FaceName
, psub
->to
.name
);
3247 /* We want a match on name and charset or just name if
3248 charset was DEFAULT_CHARSET. If the latter then
3249 we fixup the returned charset later in get_nearest_charset
3250 where we'll either use the charset of the current ansi codepage
3251 or if that's unavailable the first charset that the font supports.
3253 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3254 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3255 if(!strcmpiW(family
->FamilyName
, FaceName
)) {
3256 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3257 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3258 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3259 if(face
->scalable
|| can_use_bitmap
)
3266 * Try check the SystemLink list first for a replacement font.
3267 * We may find good replacements there.
3269 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3271 if(!strcmpiW(font_link
->font_name
, FaceName
))
3273 TRACE("found entry in system list\n");
3274 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3276 face
= font_link_entry
->face
;
3277 family
= face
->family
;
3278 if(csi
.fs
.fsCsb
[0] &
3279 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3281 if(face
->scalable
|| can_use_bitmap
)
3289 /* If requested charset was DEFAULT_CHARSET then try using charset
3290 corresponding to the current ansi codepage */
3291 if(!csi
.fs
.fsCsb
[0]) {
3293 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3294 FIXME("TCI failed on codepage %d\n", acp
);
3295 csi
.fs
.fsCsb
[0] = 0;
3297 lf
.lfCharSet
= csi
.ciCharset
;
3300 /* Face families are in the top 4 bits of lfPitchAndFamily,
3301 so mask with 0xF0 before testing */
3303 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3304 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3305 strcpyW(lf
.lfFaceName
, defFixed
);
3306 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3307 strcpyW(lf
.lfFaceName
, defSerif
);
3308 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3309 strcpyW(lf
.lfFaceName
, defSans
);
3311 strcpyW(lf
.lfFaceName
, defSans
);
3312 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3313 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3314 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3315 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3316 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3317 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3318 if(face
->scalable
|| can_use_bitmap
)
3324 last_resort_family
= NULL
;
3325 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3326 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3327 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3328 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3329 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3332 if(can_use_bitmap
&& !last_resort_family
)
3333 last_resort_family
= family
;
3338 if(last_resort_family
) {
3339 family
= last_resort_family
;
3340 csi
.fs
.fsCsb
[0] = 0;
3344 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3345 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3346 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3347 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3348 if(face
->scalable
) {
3349 csi
.fs
.fsCsb
[0] = 0;
3350 WARN("just using first face for now\n");
3353 if(can_use_bitmap
&& !last_resort_family
)
3354 last_resort_family
= family
;
3357 if(!last_resort_family
) {
3358 FIXME("can't find a single appropriate font - bailing\n");
3360 LeaveCriticalSection( &freetype_cs
);
3364 WARN("could only find a bitmap font - this will probably look awful!\n");
3365 family
= last_resort_family
;
3366 csi
.fs
.fsCsb
[0] = 0;
3369 it
= lf
.lfItalic
? 1 : 0;
3370 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3372 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
3373 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
3375 face
= best
= best_bitmap
= NULL
;
3376 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3378 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3382 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3383 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3384 new_score
= (italic
^ it
) + (bold
^ bd
);
3385 if(!best
|| new_score
<= score
)
3387 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3388 italic
, bold
, it
, bd
);
3391 if(best
->scalable
&& score
== 0) break;
3395 newdiff
= height
- (signed int)(best
->size
.height
);
3397 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3398 if(!best_bitmap
|| new_score
< score
||
3399 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3401 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3404 if(score
== 0 && diff
== 0) break;
3411 face
= best
->scalable
? best
: best_bitmap
;
3412 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3413 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3417 if(csi
.fs
.fsCsb
[0]) {
3418 ret
->charset
= lf
.lfCharSet
;
3419 ret
->codepage
= csi
.ciACP
;
3422 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3424 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3425 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3427 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3429 if(!face
->scalable
) {
3430 /* Windows uses integer scaling factors for bitmap fonts */
3431 INT scale
, scaled_height
;
3433 if (height
!= 0) height
= diff
;
3434 height
+= face
->size
.height
;
3436 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3437 scaled_height
= scale
* face
->size
.height
;
3438 /* XP allows not more than 10% deviation */
3439 if (scale
> 1 && scaled_height
- height
> scaled_height
/ 10) scale
--;
3440 ret
->scale_y
= scale
;
3442 width
= face
->size
.x_ppem
>> 6;
3443 height
= face
->size
.y_ppem
>> 6;
3447 TRACE("font scale y: %f\n", ret
->scale_y
);
3449 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3454 LeaveCriticalSection( &freetype_cs
);
3458 ret
->ntmFlags
= face
->ntmFlags
;
3460 if (ret
->charset
== SYMBOL_CHARSET
&&
3461 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3464 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3468 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3471 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3472 ret
->name
= strdupW(family
->FamilyName
);
3473 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3474 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3475 create_child_font_list(ret
);
3477 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3479 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3480 if (length
!= GDI_ERROR
)
3482 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3483 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3484 TRACE("Loaded GSUB table of %i bytes\n",length
);
3488 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3490 list_add_head(&gdi_font_list
, &ret
->entry
);
3491 LeaveCriticalSection( &freetype_cs
);
3495 static void dump_gdi_font_list(void)
3498 struct list
*elem_ptr
;
3500 TRACE("---------- gdiFont Cache ----------\n");
3501 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3502 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3503 TRACE("gdiFont=%p %s %d\n",
3504 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3507 TRACE("---------- Unused gdiFont Cache ----------\n");
3508 LIST_FOR_EACH(elem_ptr
, &unused_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
);
3515 /*************************************************************
3516 * WineEngDestroyFontInstance
3518 * free the gdiFont associated with this handle
3521 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3526 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3529 EnterCriticalSection( &freetype_cs
);
3531 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3533 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3534 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3535 if(hflist
->hfont
== handle
)
3537 TRACE("removing child font %p from child list\n", gdiFont
);
3538 list_remove(&gdiFont
->entry
);
3539 LeaveCriticalSection( &freetype_cs
);
3544 TRACE("destroying hfont=%p\n", handle
);
3546 dump_gdi_font_list();
3548 font_elem_ptr
= list_head(&gdi_font_list
);
3549 while(font_elem_ptr
) {
3550 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3551 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3553 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3554 while(hfontlist_elem_ptr
) {
3555 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3556 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3557 if(hflist
->hfont
== handle
) {
3558 list_remove(&hflist
->entry
);
3559 HeapFree(GetProcessHeap(), 0, hflist
);
3563 if(list_empty(&gdiFont
->hfontlist
)) {
3564 TRACE("Moving to Unused list\n");
3565 list_remove(&gdiFont
->entry
);
3566 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3571 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3572 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3573 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3574 while(font_elem_ptr
) {
3575 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3576 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3577 TRACE("freeing %p\n", gdiFont
);
3578 list_remove(&gdiFont
->entry
);
3581 LeaveCriticalSection( &freetype_cs
);
3585 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3586 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3591 if (face
->cached_enum_data
)
3594 *pelf
= face
->cached_enum_data
->elf
;
3595 *pntm
= face
->cached_enum_data
->ntm
;
3596 *ptype
= face
->cached_enum_data
->type
;
3600 font
= alloc_font();
3602 if(face
->scalable
) {
3603 height
= -2048; /* 2048 is the most common em size */
3606 height
= face
->size
.y_ppem
>> 6;
3607 width
= face
->size
.x_ppem
>> 6;
3609 font
->scale_y
= 1.0;
3611 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3617 font
->name
= strdupW(face
->family
->FamilyName
);
3618 font
->ntmFlags
= face
->ntmFlags
;
3620 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3622 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3624 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3626 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3627 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3629 lstrcpynW(pelf
->elfFullName
,
3630 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
3632 lstrcpynW(pelf
->elfStyle
,
3633 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
3638 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
3640 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3642 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3643 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
3644 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
3647 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
3648 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3649 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3650 pntm
->ntmFontSig
= face
->fs
;
3652 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3654 pelf
->elfLogFont
.lfEscapement
= 0;
3655 pelf
->elfLogFont
.lfOrientation
= 0;
3656 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
3657 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3658 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
3659 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
3660 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
3661 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
3662 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
3663 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3664 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3665 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3666 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3669 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
3670 *ptype
|= TRUETYPE_FONTTYPE
;
3671 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
3672 *ptype
|= DEVICE_FONTTYPE
;
3673 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
3674 *ptype
|= RASTER_FONTTYPE
;
3676 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
3677 if (face
->cached_enum_data
)
3679 face
->cached_enum_data
->elf
= *pelf
;
3680 face
->cached_enum_data
->ntm
= *pntm
;
3681 face
->cached_enum_data
->type
= *ptype
;
3687 /*************************************************************
3691 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3695 struct list
*family_elem_ptr
, *face_elem_ptr
;
3697 NEWTEXTMETRICEXW ntm
;
3706 lf
.lfCharSet
= DEFAULT_CHARSET
;
3707 lf
.lfPitchAndFamily
= 0;
3708 lf
.lfFaceName
[0] = 0;
3712 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3714 EnterCriticalSection( &freetype_cs
);
3715 if(plf
->lfFaceName
[0]) {
3717 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3720 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3721 debugstr_w(psub
->to
.name
));
3723 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3727 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3728 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3729 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3730 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3731 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3732 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3733 for(i
= 0; i
< 32; i
++) {
3734 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3735 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3736 strcpyW(elf
.elfScript
, OEM_DOSW
);
3737 i
= 32; /* break out of loop */
3738 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3741 fs
.fsCsb
[0] = 1L << i
;
3743 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3745 csi
.ciCharset
= DEFAULT_CHARSET
;
3746 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3747 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3748 elf
.elfLogFont
.lfCharSet
=
3749 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3751 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3753 FIXME("Unknown elfscript for bit %d\n", i
);
3756 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3757 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3758 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3759 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3760 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3761 ntm
.ntmTm
.ntmFlags
);
3762 /* release section before callback (FIXME) */
3763 LeaveCriticalSection( &freetype_cs
);
3764 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3765 EnterCriticalSection( &freetype_cs
);
3771 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3772 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3773 face_elem_ptr
= list_head(&family
->faces
);
3774 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3775 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3776 for(i
= 0; i
< 32; i
++) {
3777 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3778 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3779 strcpyW(elf
.elfScript
, OEM_DOSW
);
3780 i
= 32; /* break out of loop */
3781 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3784 fs
.fsCsb
[0] = 1L << i
;
3786 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3788 csi
.ciCharset
= DEFAULT_CHARSET
;
3789 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3790 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3791 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3794 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3796 FIXME("Unknown elfscript for bit %d\n", i
);
3799 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3800 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3801 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3802 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3803 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3804 ntm
.ntmTm
.ntmFlags
);
3805 /* release section before callback (FIXME) */
3806 LeaveCriticalSection( &freetype_cs
);
3807 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3808 EnterCriticalSection( &freetype_cs
);
3812 LeaveCriticalSection( &freetype_cs
);
3816 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3818 pt
->x
.value
= vec
->x
>> 6;
3819 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3820 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3821 pt
->y
.value
= vec
->y
>> 6;
3822 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3823 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3827 /***************************************************
3828 * According to the MSDN documentation on WideCharToMultiByte,
3829 * certain codepages cannot set the default_used parameter.
3830 * This returns TRUE if the codepage can set that parameter, false else
3831 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3833 static BOOL
codepage_sets_default_used(UINT codepage
)
3847 * GSUB Table handling functions
3850 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
3852 const GSUB_CoverageFormat1
* cf1
;
3854 cf1
= (GSUB_CoverageFormat1
*)table
;
3856 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
3858 int count
= GET_BE_WORD(cf1
->GlyphCount
);
3860 TRACE("Coverage Format 1, %i glyphs\n",count
);
3861 for (i
= 0; i
< count
; i
++)
3862 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
3866 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
3868 const GSUB_CoverageFormat2
* cf2
;
3871 cf2
= (GSUB_CoverageFormat2
*)cf1
;
3873 count
= GET_BE_WORD(cf2
->RangeCount
);
3874 TRACE("Coverage Format 2, %i ranges\n",count
);
3875 for (i
= 0; i
< count
; i
++)
3877 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
3879 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
3880 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
3882 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
3883 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
3889 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
3894 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
3896 const GSUB_ScriptList
*script
;
3897 const GSUB_Script
*deflt
= NULL
;
3899 script
= (GSUB_ScriptList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->ScriptList
));
3901 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
3902 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
3904 const GSUB_Script
*scr
;
3907 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
3908 scr
= (GSUB_Script
*)((LPBYTE
)script
+ offset
);
3910 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
3912 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
3918 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
3922 const GSUB_LangSys
*Lang
;
3924 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
3926 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
3928 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
3929 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
3931 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
3934 offset
= GET_BE_WORD(script
->DefaultLangSys
);
3937 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
3943 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
3946 const GSUB_FeatureList
*feature
;
3947 feature
= (GSUB_FeatureList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->FeatureList
));
3949 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
3950 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
3952 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
3953 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
3955 const GSUB_Feature
*feat
;
3956 feat
= (GSUB_Feature
*)((LPBYTE
)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
3963 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
3967 const GSUB_LookupList
*lookup
;
3968 lookup
= (GSUB_LookupList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->LookupList
));
3970 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
3971 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
3973 const GSUB_LookupTable
*look
;
3974 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
3975 look
= (GSUB_LookupTable
*)((LPBYTE
)lookup
+ offset
);
3976 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
3977 if (GET_BE_WORD(look
->LookupType
) != 1)
3978 FIXME("We only handle SubType 1\n");
3983 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
3985 const GSUB_SingleSubstFormat1
*ssf1
;
3986 offset
= GET_BE_WORD(look
->SubTable
[j
]);
3987 ssf1
= (GSUB_SingleSubstFormat1
*)((LPBYTE
)look
+offset
);
3988 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
3990 int offset
= GET_BE_WORD(ssf1
->Coverage
);
3991 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
3992 if (GSUB_is_glyph_covered((LPBYTE
)ssf1
+offset
, glyph
) != -1)
3994 TRACE(" Glyph 0x%x ->",glyph
);
3995 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
3996 TRACE(" 0x%x\n",glyph
);
4001 const GSUB_SingleSubstFormat2
*ssf2
;
4005 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
4006 offset
= GET_BE_WORD(ssf1
->Coverage
);
4007 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4008 index
= GSUB_is_glyph_covered((LPBYTE
)ssf2
+offset
, glyph
);
4009 TRACE(" Coverage index %i\n",index
);
4012 TRACE(" Glyph is 0x%x ->",glyph
);
4013 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4014 TRACE("0x%x\n",glyph
);
4023 static const char* get_opentype_script(const GdiFont
*font
)
4026 * I am not sure if this is the correct way to generate our script tag
4029 switch (font
->charset
)
4031 case ANSI_CHARSET
: return "latn";
4032 case BALTIC_CHARSET
: return "latn"; /* ?? */
4033 case CHINESEBIG5_CHARSET
: return "hani";
4034 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4035 case GB2312_CHARSET
: return "hani";
4036 case GREEK_CHARSET
: return "grek";
4037 case HANGUL_CHARSET
: return "hang";
4038 case RUSSIAN_CHARSET
: return "cyrl";
4039 case SHIFTJIS_CHARSET
: return "kana";
4040 case TURKISH_CHARSET
: return "latn"; /* ?? */
4041 case VIETNAMESE_CHARSET
: return "latn";
4042 case JOHAB_CHARSET
: return "latn"; /* ?? */
4043 case ARABIC_CHARSET
: return "arab";
4044 case HEBREW_CHARSET
: return "hebr";
4045 case THAI_CHARSET
: return "thai";
4046 default: return "latn";
4050 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4052 const GSUB_Header
*header
;
4053 const GSUB_Script
*script
;
4054 const GSUB_LangSys
*language
;
4055 const GSUB_Feature
*feature
;
4057 if (!font
->GSUB_Table
)
4060 header
= font
->GSUB_Table
;
4062 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4065 TRACE("Script not found\n");
4068 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4071 TRACE("Language not found\n");
4074 feature
= GSUB_get_feature(header
, language
, "vrt2");
4076 feature
= GSUB_get_feature(header
, language
, "vert");
4079 TRACE("vrt2/vert feature not found\n");
4082 return GSUB_apply_feature(header
, feature
, glyph
);
4085 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4089 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4090 WCHAR wc
= (WCHAR
)glyph
;
4092 BOOL
*default_used_pointer
;
4095 default_used_pointer
= NULL
;
4096 default_used
= FALSE
;
4097 if (codepage_sets_default_used(font
->codepage
))
4098 default_used_pointer
= &default_used
;
4099 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4102 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4103 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4104 return get_GSUB_vert_glyph(font
,ret
);
4107 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
&& glyph
< 0x100)
4108 glyph
= glyph
+ 0xf000;
4109 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4110 return get_GSUB_vert_glyph(font
,glyphId
);
4113 /*************************************************************
4114 * WineEngGetGlyphIndices
4117 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4118 LPWORD pgi
, DWORD flags
)
4121 int default_char
= -1;
4123 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4125 for(i
= 0; i
< count
; i
++)
4127 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4130 if (default_char
== -1)
4132 if (FT_IS_SFNT(font
->ft_face
))
4134 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4135 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4140 WineEngGetTextMetrics(font
, &textm
);
4141 default_char
= textm
.tmDefaultChar
;
4144 pgi
[i
] = default_char
;
4150 /*************************************************************
4151 * WineEngGetGlyphOutline
4153 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4154 * except that the first parameter is the HWINEENGFONT of the font in
4155 * question rather than an HDC.
4158 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4159 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4162 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4163 FT_Face ft_face
= incoming_font
->ft_face
;
4164 GdiFont
*font
= incoming_font
;
4165 FT_UInt glyph_index
;
4166 DWORD width
, height
, pitch
, needed
= 0;
4167 FT_Bitmap ft_bitmap
;
4169 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4171 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4172 float widthRatio
= 1.0;
4173 FT_Matrix transMat
= identityMat
;
4174 BOOL needsTransform
= FALSE
;
4175 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4176 UINT original_index
;
4179 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4180 buflen
, buf
, lpmat
);
4182 EnterCriticalSection( &freetype_cs
);
4184 if(format
& GGO_GLYPH_INDEX
) {
4185 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4186 original_index
= glyph
;
4187 format
&= ~GGO_GLYPH_INDEX
;
4189 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4190 ft_face
= font
->ft_face
;
4191 original_index
= glyph_index
;
4194 /* tategaki never appears to happen to lower glyph index */
4195 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4198 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4199 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4200 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4201 font
->gmsize
* sizeof(GM
*));
4203 if(format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&& FONT_GM(font
,original_index
)->init
) {
4204 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4205 LeaveCriticalSection( &freetype_cs
);
4206 return 1; /* FIXME */
4210 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4211 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4213 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) || lpmat
)
4214 load_flags
|= FT_LOAD_NO_BITMAP
;
4216 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4219 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4220 LeaveCriticalSection( &freetype_cs
);
4224 /* Scaling factor */
4225 if (font
->aveWidth
&& font
->potm
)
4227 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4228 widthRatio
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4231 widthRatio
= font
->scale_y
;
4233 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
4234 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
4236 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
4238 bbx
= (right
- left
) >> 6;
4240 /* Scaling transform */
4241 if(font
->aveWidth
) {
4243 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4246 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4248 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4249 needsTransform
= TRUE
;
4252 /* Slant transform */
4253 if (font
->fake_italic
) {
4256 slantMat
.xx
= (1 << 16);
4257 slantMat
.xy
= ((1 << 16) >> 2);
4259 slantMat
.yy
= (1 << 16);
4260 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4261 needsTransform
= TRUE
;
4264 /* Rotation transform */
4265 if(font
->orientation
&& !tategaki
) {
4266 FT_Matrix rotationMat
;
4268 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
4269 pFT_Vector_Unit(&vecAngle
, angle
);
4270 rotationMat
.xx
= vecAngle
.x
;
4271 rotationMat
.xy
= -vecAngle
.y
;
4272 rotationMat
.yx
= -rotationMat
.xy
;
4273 rotationMat
.yy
= rotationMat
.xx
;
4275 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4276 needsTransform
= TRUE
;
4279 /* Extra transformation specified by caller */
4282 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4283 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
4284 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
4285 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4286 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4287 needsTransform
= TRUE
;
4290 if(!needsTransform
) {
4291 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4292 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4293 ft_face
->glyph
->metrics
.height
) & -64;
4294 lpgm
->gmCellIncX
= adv
;
4295 lpgm
->gmCellIncY
= 0;
4299 for(xc
= 0; xc
< 2; xc
++) {
4300 for(yc
= 0; yc
< 2; yc
++) {
4301 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4302 xc
* ft_face
->glyph
->metrics
.width
);
4303 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4304 yc
* ft_face
->glyph
->metrics
.height
;
4305 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4306 pFT_Vector_Transform(&vec
, &transMat
);
4307 if(xc
== 0 && yc
== 0) {
4308 left
= right
= vec
.x
;
4309 top
= bottom
= vec
.y
;
4311 if(vec
.x
< left
) left
= vec
.x
;
4312 else if(vec
.x
> right
) right
= vec
.x
;
4313 if(vec
.y
< bottom
) bottom
= vec
.y
;
4314 else if(vec
.y
> top
) top
= vec
.y
;
4319 right
= (right
+ 63) & -64;
4320 bottom
= bottom
& -64;
4321 top
= (top
+ 63) & -64;
4323 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4324 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4326 pFT_Vector_Transform(&vec
, &transMat
);
4327 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4328 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4330 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4331 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4332 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4333 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4335 if(format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
)
4337 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4338 FONT_GM(font
,original_index
)->adv
= adv
;
4339 FONT_GM(font
,original_index
)->lsb
= lsb
;
4340 FONT_GM(font
,original_index
)->bbx
= bbx
;
4341 FONT_GM(font
,original_index
)->init
= TRUE
;
4344 if(format
== GGO_METRICS
)
4346 LeaveCriticalSection( &freetype_cs
);
4347 return 1; /* FIXME */
4350 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) {
4351 TRACE("loaded a bitmap\n");
4352 LeaveCriticalSection( &freetype_cs
);
4358 width
= lpgm
->gmBlackBoxX
;
4359 height
= lpgm
->gmBlackBoxY
;
4360 pitch
= ((width
+ 31) >> 5) << 2;
4361 needed
= pitch
* height
;
4363 if(!buf
|| !buflen
) break;
4365 switch(ft_face
->glyph
->format
) {
4366 case ft_glyph_format_bitmap
:
4368 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4369 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4370 INT h
= ft_face
->glyph
->bitmap
.rows
;
4372 memcpy(dst
, src
, w
);
4373 src
+= ft_face
->glyph
->bitmap
.pitch
;
4379 case ft_glyph_format_outline
:
4380 ft_bitmap
.width
= width
;
4381 ft_bitmap
.rows
= height
;
4382 ft_bitmap
.pitch
= pitch
;
4383 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4384 ft_bitmap
.buffer
= buf
;
4386 if(needsTransform
) {
4387 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4390 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4392 /* Note: FreeType will only set 'black' bits for us. */
4393 memset(buf
, 0, needed
);
4394 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4398 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4399 LeaveCriticalSection( &freetype_cs
);
4404 case GGO_GRAY2_BITMAP
:
4405 case GGO_GRAY4_BITMAP
:
4406 case GGO_GRAY8_BITMAP
:
4407 case WINE_GGO_GRAY16_BITMAP
:
4409 unsigned int mult
, row
, col
;
4412 width
= lpgm
->gmBlackBoxX
;
4413 height
= lpgm
->gmBlackBoxY
;
4414 pitch
= (width
+ 3) / 4 * 4;
4415 needed
= pitch
* height
;
4417 if(!buf
|| !buflen
) break;
4419 switch(ft_face
->glyph
->format
) {
4420 case ft_glyph_format_bitmap
:
4422 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4423 INT h
= ft_face
->glyph
->bitmap
.rows
;
4426 for(x
= 0; x
< pitch
; x
++)
4428 if(x
< ft_face
->glyph
->bitmap
.width
)
4429 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
4433 src
+= ft_face
->glyph
->bitmap
.pitch
;
4436 LeaveCriticalSection( &freetype_cs
);
4439 case ft_glyph_format_outline
:
4441 ft_bitmap
.width
= width
;
4442 ft_bitmap
.rows
= height
;
4443 ft_bitmap
.pitch
= pitch
;
4444 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4445 ft_bitmap
.buffer
= buf
;
4448 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4450 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4452 memset(ft_bitmap
.buffer
, 0, buflen
);
4454 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4456 if(format
== GGO_GRAY2_BITMAP
)
4458 else if(format
== GGO_GRAY4_BITMAP
)
4460 else if(format
== GGO_GRAY8_BITMAP
)
4462 else /* format == WINE_GGO_GRAY16_BITMAP */
4464 LeaveCriticalSection( &freetype_cs
);
4470 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4471 LeaveCriticalSection( &freetype_cs
);
4476 for(row
= 0; row
< height
; row
++) {
4478 for(col
= 0; col
< width
; col
++, ptr
++) {
4479 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4488 int contour
, point
= 0, first_pt
;
4489 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4490 TTPOLYGONHEADER
*pph
;
4492 DWORD pph_start
, cpfx
, type
;
4494 if(buflen
== 0) buf
= NULL
;
4496 if (needsTransform
&& buf
) {
4497 pFT_Outline_Transform(outline
, &transMat
);
4500 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4502 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4505 pph
->dwType
= TT_POLYGON_TYPE
;
4506 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4508 needed
+= sizeof(*pph
);
4510 while(point
<= outline
->contours
[contour
]) {
4511 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4512 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4513 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
4517 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4520 } while(point
<= outline
->contours
[contour
] &&
4521 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4522 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4523 /* At the end of a contour Windows adds the start point, but
4525 if(point
> outline
->contours
[contour
] &&
4526 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4528 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
4530 } else if(point
<= outline
->contours
[contour
] &&
4531 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4532 /* add closing pt for bezier */
4534 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4542 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4545 pph
->cb
= needed
- pph_start
;
4551 /* Convert the quadratic Beziers to cubic Beziers.
4552 The parametric eqn for a cubic Bezier is, from PLRM:
4553 r(t) = at^3 + bt^2 + ct + r0
4554 with the control points:
4559 A quadratic Beizer has the form:
4560 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4562 So equating powers of t leads to:
4563 r1 = 2/3 p1 + 1/3 p0
4564 r2 = 2/3 p1 + 1/3 p2
4565 and of course r0 = p0, r3 = p2
4568 int contour
, point
= 0, first_pt
;
4569 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4570 TTPOLYGONHEADER
*pph
;
4572 DWORD pph_start
, cpfx
, type
;
4573 FT_Vector cubic_control
[4];
4574 if(buflen
== 0) buf
= NULL
;
4576 if (needsTransform
&& buf
) {
4577 pFT_Outline_Transform(outline
, &transMat
);
4580 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4582 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4585 pph
->dwType
= TT_POLYGON_TYPE
;
4586 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4588 needed
+= sizeof(*pph
);
4590 while(point
<= outline
->contours
[contour
]) {
4591 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4592 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4593 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
4596 if(type
== TT_PRIM_LINE
) {
4598 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4602 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4605 /* FIXME: Possible optimization in endpoint calculation
4606 if there are two consecutive curves */
4607 cubic_control
[0] = outline
->points
[point
-1];
4608 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4609 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
4610 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
4611 cubic_control
[0].x
>>= 1;
4612 cubic_control
[0].y
>>= 1;
4614 if(point
+1 > outline
->contours
[contour
])
4615 cubic_control
[3] = outline
->points
[first_pt
];
4617 cubic_control
[3] = outline
->points
[point
+1];
4618 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
4619 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
4620 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
4621 cubic_control
[3].x
>>= 1;
4622 cubic_control
[3].y
>>= 1;
4625 /* r1 = 1/3 p0 + 2/3 p1
4626 r2 = 1/3 p2 + 2/3 p1 */
4627 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
4628 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
4629 cubic_control
[2] = cubic_control
[1];
4630 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
4631 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
4632 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
4633 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
4635 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
4636 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
4637 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
4642 } while(point
<= outline
->contours
[contour
] &&
4643 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4644 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4645 /* At the end of a contour Windows adds the start point,
4646 but only for Beziers and we've already done that.
4648 if(point
<= outline
->contours
[contour
] &&
4649 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4650 /* This is the closing pt of a bezier, but we've already
4651 added it, so just inc point and carry on */
4658 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4661 pph
->cb
= needed
- pph_start
;
4667 FIXME("Unsupported format %d\n", format
);
4668 LeaveCriticalSection( &freetype_cs
);
4671 LeaveCriticalSection( &freetype_cs
);
4675 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
4677 FT_Face ft_face
= font
->ft_face
;
4678 #ifdef HAVE_FREETYPE_FTWINFNT_H
4679 FT_WinFNT_HeaderRec winfnt_header
;
4681 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
4682 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
4683 font
->potm
->otmSize
= size
;
4685 #define TM font->potm->otmTextMetrics
4686 #ifdef HAVE_FREETYPE_FTWINFNT_H
4687 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
4689 TM
.tmHeight
= winfnt_header
.pixel_height
;
4690 TM
.tmAscent
= winfnt_header
.ascent
;
4691 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
4692 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
4693 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
4694 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
4695 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4696 TM
.tmWeight
= winfnt_header
.weight
;
4698 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4699 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4700 TM
.tmFirstChar
= winfnt_header
.first_char
;
4701 TM
.tmLastChar
= winfnt_header
.last_char
;
4702 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4703 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4704 TM
.tmItalic
= winfnt_header
.italic
;
4705 TM
.tmUnderlined
= font
->underline
;
4706 TM
.tmStruckOut
= font
->strikeout
;
4707 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4708 TM
.tmCharSet
= winfnt_header
.charset
;
4713 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4714 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4715 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4716 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4717 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4718 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4719 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4720 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4722 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4723 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4725 TM
.tmLastChar
= 255;
4726 TM
.tmDefaultChar
= 32;
4727 TM
.tmBreakChar
= 32;
4728 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4729 TM
.tmUnderlined
= font
->underline
;
4730 TM
.tmStruckOut
= font
->strikeout
;
4731 /* NB inverted meaning of TMPF_FIXED_PITCH */
4732 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4733 TM
.tmCharSet
= font
->charset
;
4741 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
4747 scale_x
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4748 scale_x
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4751 scale_x
= font
->scale_y
;
4753 ptm
->tmHeight
= (float)ptm
->tmHeight
* font
->scale_y
;
4754 ptm
->tmAscent
= (float)ptm
->tmAscent
* font
->scale_y
;
4755 ptm
->tmDescent
= (float)ptm
->tmDescent
* font
->scale_y
;
4756 ptm
->tmInternalLeading
= (float)ptm
->tmInternalLeading
* font
->scale_y
;
4757 ptm
->tmExternalLeading
= (float)ptm
->tmExternalLeading
* font
->scale_y
;
4759 ptm
->tmAveCharWidth
= (float)ptm
->tmAveCharWidth
* scale_x
;
4760 ptm
->tmMaxCharWidth
= (float)ptm
->tmMaxCharWidth
* scale_x
;
4763 /*************************************************************
4764 * WineEngGetTextMetrics
4767 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4769 EnterCriticalSection( &freetype_cs
);
4771 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4772 if(!get_bitmap_text_metrics(font
))
4774 LeaveCriticalSection( &freetype_cs
);
4780 LeaveCriticalSection( &freetype_cs
);
4783 *ptm
= font
->potm
->otmTextMetrics
;
4784 scale_font_metrics(font
, ptm
);
4785 LeaveCriticalSection( &freetype_cs
);
4790 /*************************************************************
4791 * WineEngGetOutlineTextMetrics
4794 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4795 OUTLINETEXTMETRICW
*potm
)
4797 FT_Face ft_face
= font
->ft_face
;
4798 UINT needed
, lenfam
, lensty
, ret
;
4800 TT_HoriHeader
*pHori
;
4801 TT_Postscript
*pPost
;
4802 FT_Fixed x_scale
, y_scale
;
4803 WCHAR
*family_nameW
, *style_nameW
;
4804 static const WCHAR spaceW
[] = {' ', '\0'};
4806 INT ascent
, descent
;
4808 TRACE("font=%p\n", font
);
4810 if(!FT_IS_SCALABLE(ft_face
))
4813 EnterCriticalSection( &freetype_cs
);
4816 if(cbSize
>= font
->potm
->otmSize
)
4818 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4819 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4821 LeaveCriticalSection( &freetype_cs
);
4822 return font
->potm
->otmSize
;
4826 needed
= sizeof(*potm
);
4828 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
4829 family_nameW
= strdupW(font
->name
);
4831 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
4833 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
4834 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
4835 style_nameW
, lensty
/sizeof(WCHAR
));
4837 /* These names should be read from the TT name table */
4839 /* length of otmpFamilyName */
4842 /* length of otmpFaceName */
4843 if(!strcasecmp(ft_face
->style_name
, "regular")) {
4844 needed
+= lenfam
; /* just the family name */
4846 needed
+= lenfam
+ lensty
; /* family + " " + style */
4849 /* length of otmpStyleName */
4852 /* length of otmpFullName */
4853 needed
+= lenfam
+ lensty
;
4856 x_scale
= ft_face
->size
->metrics
.x_scale
;
4857 y_scale
= ft_face
->size
->metrics
.y_scale
;
4859 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4861 FIXME("Can't find OS/2 table - not TT font?\n");
4866 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4868 FIXME("Can't find HHEA table - not TT font?\n");
4873 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
4875 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",
4876 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
4877 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
4878 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
4879 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
4880 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
4882 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
4883 font
->potm
->otmSize
= needed
;
4885 #define TM font->potm->otmTextMetrics
4887 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
4888 ascent
= pHori
->Ascender
;
4889 descent
= -pHori
->Descender
;
4891 ascent
= pOS2
->usWinAscent
;
4892 descent
= pOS2
->usWinDescent
;
4896 TM
.tmAscent
= font
->yMax
;
4897 TM
.tmDescent
= -font
->yMin
;
4898 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4900 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4901 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4902 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4903 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4906 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4909 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4911 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4912 ((ascent
+ descent
) -
4913 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4915 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4916 if (TM
.tmAveCharWidth
== 0) {
4917 TM
.tmAveCharWidth
= 1;
4919 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4920 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4922 TM
.tmDigitizedAspectX
= 300;
4923 TM
.tmDigitizedAspectY
= 300;
4924 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4925 * symbol range to 0 - f0ff
4927 if (font
->charset
== SYMBOL_CHARSET
)
4930 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4931 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4932 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4933 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4934 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4935 TM
.tmUnderlined
= font
->underline
;
4936 TM
.tmStruckOut
= font
->strikeout
;
4938 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4939 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4940 (pOS2
->version
== 0xFFFFU
||
4941 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4942 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4944 TM
.tmPitchAndFamily
= 0;
4946 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4947 case PAN_FAMILY_SCRIPT
:
4948 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4950 case PAN_FAMILY_DECORATIVE
:
4951 case PAN_FAMILY_PICTORIAL
:
4952 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4954 case PAN_FAMILY_TEXT_DISPLAY
:
4955 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4956 TM
.tmPitchAndFamily
= FF_MODERN
;
4958 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4959 case PAN_SERIF_NORMAL_SANS
:
4960 case PAN_SERIF_OBTUSE_SANS
:
4961 case PAN_SERIF_PERP_SANS
:
4962 TM
.tmPitchAndFamily
|= FF_SWISS
;
4965 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4970 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4973 if(FT_IS_SCALABLE(ft_face
))
4974 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4976 if(FT_IS_SFNT(ft_face
))
4978 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
4979 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
4981 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4984 TM
.tmCharSet
= font
->charset
;
4987 font
->potm
->otmFiller
= 0;
4988 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4989 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4990 font
->potm
->otmfsType
= pOS2
->fsType
;
4991 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4992 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4993 font
->potm
->otmItalicAngle
= 0; /* POST table */
4994 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4995 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4996 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4997 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4998 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4999 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5000 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5001 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5002 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5003 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5004 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
5005 font
->potm
->otmMacDescent
= 0;
5006 font
->potm
->otmMacLineGap
= 0;
5007 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5008 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5009 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5010 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5011 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5012 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5013 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5014 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5015 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5016 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5017 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5019 font
->potm
->otmsUnderscoreSize
= 0;
5020 font
->potm
->otmsUnderscorePosition
= 0;
5022 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5023 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5026 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5027 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5028 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5029 strcpyW((WCHAR
*)cp
, family_nameW
);
5031 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5032 strcpyW((WCHAR
*)cp
, style_nameW
);
5034 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5035 strcpyW((WCHAR
*)cp
, family_nameW
);
5036 if(strcasecmp(ft_face
->style_name
, "regular")) {
5037 strcatW((WCHAR
*)cp
, spaceW
);
5038 strcatW((WCHAR
*)cp
, style_nameW
);
5039 cp
+= lenfam
+ lensty
;
5042 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5043 strcpyW((WCHAR
*)cp
, family_nameW
);
5044 strcatW((WCHAR
*)cp
, spaceW
);
5045 strcatW((WCHAR
*)cp
, style_nameW
);
5048 if(potm
&& needed
<= cbSize
)
5050 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5051 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5055 HeapFree(GetProcessHeap(), 0, style_nameW
);
5056 HeapFree(GetProcessHeap(), 0, family_nameW
);
5058 LeaveCriticalSection( &freetype_cs
);
5062 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5064 HFONTLIST
*hfontlist
;
5065 child
->font
= alloc_font();
5066 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5067 if(!child
->font
->ft_face
)
5069 free_font(child
->font
);
5074 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5075 child
->font
->orientation
= font
->orientation
;
5076 child
->font
->scale_y
= font
->scale_y
;
5077 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5078 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5079 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5080 child
->font
->base_font
= font
;
5081 list_add_head(&child_font_list
, &child
->font
->entry
);
5082 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5086 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5089 CHILD_FONT
*child_font
;
5092 font
= font
->base_font
;
5094 *linked_font
= font
;
5096 if((*glyph
= get_glyph_index(font
, c
)))
5099 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5101 if(!child_font
->font
)
5102 if(!load_child_font(font
, child_font
))
5105 if(!child_font
->font
->ft_face
)
5107 g
= get_glyph_index(child_font
->font
, c
);
5111 *linked_font
= child_font
->font
;
5118 /*************************************************************
5119 * WineEngGetCharWidth
5122 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5127 FT_UInt glyph_index
;
5128 GdiFont
*linked_font
;
5130 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5132 EnterCriticalSection( &freetype_cs
);
5133 for(c
= firstChar
; c
<= lastChar
; c
++) {
5134 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5135 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5136 &gm
, 0, NULL
, NULL
);
5137 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5139 LeaveCriticalSection( &freetype_cs
);
5143 /*************************************************************
5144 * WineEngGetCharABCWidths
5147 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5152 FT_UInt glyph_index
;
5153 GdiFont
*linked_font
;
5155 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5157 if(!FT_IS_SCALABLE(font
->ft_face
))
5160 EnterCriticalSection( &freetype_cs
);
5162 for(c
= firstChar
; c
<= lastChar
; c
++) {
5163 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5164 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5165 &gm
, 0, NULL
, NULL
);
5166 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
5167 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
5168 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
5169 FONT_GM(linked_font
,glyph_index
)->bbx
;
5171 LeaveCriticalSection( &freetype_cs
);
5175 /*************************************************************
5176 * WineEngGetCharABCWidthsI
5179 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5184 FT_UInt glyph_index
;
5185 GdiFont
*linked_font
;
5187 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
5190 EnterCriticalSection( &freetype_cs
);
5192 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
5194 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
5195 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5196 &gm
, 0, NULL
, NULL
);
5197 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
5198 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
5199 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
5200 - FONT_GM(linked_font
,c
)->bbx
;
5203 for(c
= 0; c
< count
; c
++) {
5204 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
5205 &gm
, 0, NULL
, NULL
);
5206 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
5207 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
5208 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
5209 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
5212 LeaveCriticalSection( &freetype_cs
);
5216 /*************************************************************
5217 * WineEngGetTextExtentExPoint
5220 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5221 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5227 FT_UInt glyph_index
;
5228 GdiFont
*linked_font
;
5230 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
5233 EnterCriticalSection( &freetype_cs
);
5236 WineEngGetTextMetrics(font
, &tm
);
5237 size
->cy
= tm
.tmHeight
;
5239 for(idx
= 0; idx
< count
; idx
++) {
5240 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
5241 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5242 &gm
, 0, NULL
, NULL
);
5243 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
5245 if (! pnfit
|| ext
<= max_ext
) {
5255 LeaveCriticalSection( &freetype_cs
);
5256 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5260 /*************************************************************
5261 * WineEngGetTextExtentExPointI
5264 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5265 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5272 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
5274 EnterCriticalSection( &freetype_cs
);
5277 WineEngGetTextMetrics(font
, &tm
);
5278 size
->cy
= tm
.tmHeight
;
5280 for(idx
= 0; idx
< count
; idx
++) {
5281 WineEngGetGlyphOutline(font
, indices
[idx
],
5282 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
5284 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
5286 if (! pnfit
|| ext
<= max_ext
) {
5296 LeaveCriticalSection( &freetype_cs
);
5297 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5301 /*************************************************************
5302 * WineEngGetFontData
5305 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5308 FT_Face ft_face
= font
->ft_face
;
5312 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5313 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
5314 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
5316 if(!FT_IS_SFNT(ft_face
))
5324 if(table
) { /* MS tags differ in endianness from FT ones */
5325 table
= table
>> 24 | table
<< 24 |
5326 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
5329 /* make sure value of len is the value freetype says it needs */
5332 FT_ULong needed
= 0;
5333 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
5334 if( !err
&& needed
< len
) len
= needed
;
5336 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
5339 TRACE("Can't find table %c%c%c%c\n",
5340 /* bytes were reversed */
5341 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
5342 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
5348 /*************************************************************
5349 * WineEngGetTextFace
5352 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5355 lstrcpynW(str
, font
->name
, count
);
5356 return strlenW(font
->name
);
5358 return strlenW(font
->name
) + 1;
5361 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5363 if (fs
) *fs
= font
->fs
;
5364 return font
->charset
;
5367 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5369 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
5370 struct list
*first_hfont
;
5373 EnterCriticalSection( &freetype_cs
);
5374 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
5375 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
5376 if(font
== linked_font
)
5377 *new_hfont
= dc
->hFont
;
5380 first_hfont
= list_head(&linked_font
->hfontlist
);
5381 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
5383 LeaveCriticalSection( &freetype_cs
);
5387 /* Retrieve a list of supported Unicode ranges for a given font.
5388 * Can be called with NULL gs to calculate the buffer size. Returns
5389 * the number of ranges found.
5391 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
5393 DWORD num_ranges
= 0;
5395 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5398 FT_ULong char_code
, char_code_prev
;
5401 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
5403 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5404 face
->num_glyphs
, glyph_code
, char_code
);
5406 if (!glyph_code
) return 0;
5410 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
5411 gs
->ranges
[0].cGlyphs
= 0;
5412 gs
->cGlyphsSupported
= 0;
5418 if (char_code
< char_code_prev
)
5420 ERR("expected increasing char code from FT_Get_Next_Char\n");
5423 if (char_code
- char_code_prev
> 1)
5428 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
5429 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
5430 gs
->cGlyphsSupported
++;
5435 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
5436 gs
->cGlyphsSupported
++;
5438 char_code_prev
= char_code
;
5439 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
5443 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
5448 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5451 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
5453 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
5456 glyphset
->cbThis
= size
;
5457 glyphset
->cRanges
= num_ranges
;
5462 /*************************************************************
5465 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5468 EnterCriticalSection( &freetype_cs
);
5469 ret
= !list_empty(&font
->child_fonts
);
5470 LeaveCriticalSection( &freetype_cs
);
5474 static BOOL
is_hinting_enabled(void)
5476 /* Use the >= 2.2.0 function if available */
5477 if(pFT_Get_TrueType_Engine_Type
)
5479 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
5480 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
5482 #ifdef FT_DRIVER_HAS_HINTER
5487 /* otherwise if we've been compiled with < 2.2.0 headers
5488 use the internal macro */
5489 mod
= pFT_Get_Module(library
, "truetype");
5490 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
5498 /*************************************************************************
5499 * GetRasterizerCaps (GDI32.@)
5501 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5503 static int hinting
= -1;
5507 hinting
= is_hinting_enabled();
5508 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
5511 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5512 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
5513 lprs
->nLanguageID
= 0;
5517 /*************************************************************************
5518 * Kerning support for TrueType fonts
5520 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5522 struct TT_kern_table
5528 struct TT_kern_subtable
5537 USHORT horizontal
: 1;
5539 USHORT cross_stream
: 1;
5540 USHORT override
: 1;
5541 USHORT reserved1
: 4;
5547 struct TT_format0_kern_subtable
5551 USHORT entrySelector
;
5562 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
5563 const struct TT_format0_kern_subtable
*tt_f0_ks
,
5564 const USHORT
*glyph_to_char
,
5565 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
5568 const struct TT_kern_pair
*tt_kern_pair
;
5570 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
5572 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
5574 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5575 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
5576 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
5578 if (!kern_pair
|| !cPairs
)
5581 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
5583 nPairs
= min(nPairs
, cPairs
);
5585 for (i
= 0; i
< nPairs
; i
++)
5587 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
5588 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
5589 /* this algorithm appears to better match what Windows does */
5590 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
5591 if (kern_pair
->iKernAmount
< 0)
5593 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
5594 kern_pair
->iKernAmount
-= font
->ppem
;
5596 else if (kern_pair
->iKernAmount
> 0)
5598 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
5599 kern_pair
->iKernAmount
+= font
->ppem
;
5601 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
5603 TRACE("left %u right %u value %d\n",
5604 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
5608 TRACE("copied %u entries\n", nPairs
);
5612 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5616 const struct TT_kern_table
*tt_kern_table
;
5617 const struct TT_kern_subtable
*tt_kern_subtable
;
5619 USHORT
*glyph_to_char
;
5621 EnterCriticalSection( &freetype_cs
);
5622 if (font
->total_kern_pairs
!= (DWORD
)-1)
5624 if (cPairs
&& kern_pair
)
5626 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5627 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5628 LeaveCriticalSection( &freetype_cs
);
5631 LeaveCriticalSection( &freetype_cs
);
5632 return font
->total_kern_pairs
;
5635 font
->total_kern_pairs
= 0;
5637 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
5639 if (length
== GDI_ERROR
)
5641 TRACE("no kerning data in the font\n");
5642 LeaveCriticalSection( &freetype_cs
);
5646 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
5649 WARN("Out of memory\n");
5650 LeaveCriticalSection( &freetype_cs
);
5654 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
5656 /* build a glyph index to char code map */
5657 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
5660 WARN("Out of memory allocating a glyph index to char code map\n");
5661 HeapFree(GetProcessHeap(), 0, buf
);
5662 LeaveCriticalSection( &freetype_cs
);
5666 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5672 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
5674 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5675 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
5679 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5681 /* FIXME: This doesn't match what Windows does: it does some fancy
5682 * things with duplicate glyph index to char code mappings, while
5683 * we just avoid overriding existing entries.
5685 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
5686 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
5688 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
5695 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
5696 for (n
= 0; n
<= 65535; n
++)
5697 glyph_to_char
[n
] = (USHORT
)n
;
5700 tt_kern_table
= buf
;
5701 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
5702 TRACE("version %u, nTables %u\n",
5703 GET_BE_WORD(tt_kern_table
->version
), nTables
);
5705 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
5707 for (i
= 0; i
< nTables
; i
++)
5709 struct TT_kern_subtable tt_kern_subtable_copy
;
5711 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
5712 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
5713 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
5715 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5716 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
5717 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
5719 /* According to the TrueType specification this is the only format
5720 * that will be properly interpreted by Windows and OS/2
5722 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
5724 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
5726 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5727 glyph_to_char
, NULL
, 0);
5728 font
->total_kern_pairs
+= new_chunk
;
5730 if (!font
->kern_pairs
)
5731 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
5732 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5734 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
5735 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5737 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5738 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
5741 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
5743 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
5746 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
5747 HeapFree(GetProcessHeap(), 0, buf
);
5749 if (cPairs
&& kern_pair
)
5751 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5752 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5753 LeaveCriticalSection( &freetype_cs
);
5756 LeaveCriticalSection( &freetype_cs
);
5757 return font
->total_kern_pairs
;
5760 #else /* HAVE_FREETYPE */
5762 /*************************************************************************/
5764 BOOL
WineEngInit(void)
5768 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
5772 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
5777 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5782 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
5783 LPWORD pgi
, DWORD flags
)
5788 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
5789 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5792 ERR("called but we don't have FreeType\n");
5796 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5798 ERR("called but we don't have FreeType\n");
5802 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5803 OUTLINETEXTMETRICW
*potm
)
5805 ERR("called but we don't have FreeType\n");
5809 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5812 ERR("called but we don't have FreeType\n");
5816 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5819 ERR("called but we don't have FreeType\n");
5823 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5826 ERR("called but we don't have FreeType\n");
5830 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5831 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5833 ERR("called but we don't have FreeType\n");
5837 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5838 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5840 ERR("called but we don't have FreeType\n");
5844 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5847 ERR("called but we don't have FreeType\n");
5851 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5853 ERR("called but we don't have FreeType\n");
5857 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5863 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5869 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
5875 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5878 return DEFAULT_CHARSET
;
5881 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5886 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5888 FIXME("(%p, %p): stub\n", font
, glyphset
);
5892 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5897 /*************************************************************************
5898 * GetRasterizerCaps (GDI32.@)
5900 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5902 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5904 lprs
->nLanguageID
= 0;
5908 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5910 ERR("called but we don't have FreeType\n");
5914 #endif /* HAVE_FREETYPE */