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 #ifdef FT_MULFIX_INLINED
167 #define pFT_MulFix FT_MULFIX_INLINED
169 MAKE_FUNCPTR(FT_MulFix
);
171 MAKE_FUNCPTR(FT_New_Face
);
172 MAKE_FUNCPTR(FT_New_Memory_Face
);
173 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
174 MAKE_FUNCPTR(FT_Outline_Transform
);
175 MAKE_FUNCPTR(FT_Outline_Translate
);
176 MAKE_FUNCPTR(FT_Select_Charmap
);
177 MAKE_FUNCPTR(FT_Set_Charmap
);
178 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
179 MAKE_FUNCPTR(FT_Vector_Transform
);
180 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
181 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
182 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
183 static FT_ULong (*pFT_Get_Next_Char
)(FT_Face
,FT_ULong
,FT_UInt
*);
184 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
185 #ifdef HAVE_FREETYPE_FTWINFNT_H
186 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
189 #ifdef SONAME_LIBFONTCONFIG
190 #include <fontconfig/fontconfig.h>
191 MAKE_FUNCPTR(FcConfigGetCurrent
);
192 MAKE_FUNCPTR(FcFontList
);
193 MAKE_FUNCPTR(FcFontSetDestroy
);
194 MAKE_FUNCPTR(FcInit
);
195 MAKE_FUNCPTR(FcObjectSetAdd
);
196 MAKE_FUNCPTR(FcObjectSetCreate
);
197 MAKE_FUNCPTR(FcObjectSetDestroy
);
198 MAKE_FUNCPTR(FcPatternCreate
);
199 MAKE_FUNCPTR(FcPatternDestroy
);
200 MAKE_FUNCPTR(FcPatternGetBool
);
201 MAKE_FUNCPTR(FcPatternGetString
);
207 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
208 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
209 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
212 #ifndef ft_encoding_none
213 #define FT_ENCODING_NONE ft_encoding_none
215 #ifndef ft_encoding_ms_symbol
216 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
218 #ifndef ft_encoding_unicode
219 #define FT_ENCODING_UNICODE ft_encoding_unicode
221 #ifndef ft_encoding_apple_roman
222 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
225 #ifdef WORDS_BIGENDIAN
226 #define GET_BE_WORD(x) (x)
228 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
231 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
238 FT_Short internal_leading
;
241 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
242 So to let this compile on older versions of FreeType we'll define the
243 new structure here. */
245 FT_Short height
, width
;
246 FT_Pos size
, x_ppem
, y_ppem
;
252 NEWTEXTMETRICEXW ntm
;
256 typedef struct tagFace
{
261 DWORD font_data_size
;
264 FONTSIGNATURE fs_links
;
266 FT_Fixed font_version
;
268 Bitmap_Size size
; /* set if face is a bitmap */
269 BOOL external
; /* TRUE if we should manually add this font to the registry */
270 struct tagFamily
*family
;
271 /* Cached data for Enum */
272 struct enum_data
*cached_enum_data
;
275 typedef struct tagFamily
{
277 const WCHAR
*FamilyName
;
283 INT adv
; /* These three hold to widths of the unrotated chars */
301 typedef struct tagHFONTLIST
{
316 struct list hfontlist
;
317 OUTLINETEXTMETRICW
*potm
;
318 DWORD total_kern_pairs
;
319 KERNINGPAIR
*kern_pairs
;
320 struct list child_fonts
;
322 /* the following members can be accessed without locking, they are never modified after creation */
324 struct font_mapping
*mapping
;
347 const WCHAR
*font_name
;
351 #define GM_BLOCK_SIZE 128
352 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
354 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
355 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
356 #define UNUSED_CACHE_SIZE 10
357 static struct list child_font_list
= LIST_INIT(child_font_list
);
358 static struct list system_links
= LIST_INIT(system_links
);
360 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
362 static struct list font_list
= LIST_INIT(font_list
);
364 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
365 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
366 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
368 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
369 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
370 'W','i','n','d','o','w','s','\\',
371 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
372 'F','o','n','t','s','\0'};
374 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
375 'W','i','n','d','o','w','s',' ','N','T','\\',
376 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
377 'F','o','n','t','s','\0'};
379 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
380 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
381 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
382 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
384 static const WCHAR
* const SystemFontValues
[4] = {
391 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
392 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
394 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
395 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
396 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
397 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
398 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
399 'E','u','r','o','p','e','a','n','\0'};
400 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
401 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
402 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
403 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
404 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
405 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
406 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
407 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
408 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
409 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
410 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
411 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
413 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
423 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
431 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
440 typedef struct tagFontSubst
{
456 static struct list mappings_list
= LIST_INIT( mappings_list
);
458 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
460 static CRITICAL_SECTION freetype_cs
;
461 static CRITICAL_SECTION_DEBUG critsect_debug
=
464 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
465 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
467 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
469 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
471 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
472 static BOOL use_default_fallback
= FALSE
;
474 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
476 /****************************************
477 * Notes on .fon files
479 * The fonts System, FixedSys and Terminal are special. There are typically multiple
480 * versions installed for different resolutions and codepages. Windows stores which one to use
481 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
483 * FIXEDFON.FON FixedSys
485 * OEMFONT.FON Terminal
486 * LogPixels Current dpi set by the display control panel applet
487 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
488 * also has a LogPixels value that appears to mirror this)
490 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
491 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
492 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
493 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
494 * so that makes sense.
496 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
497 * to be mapped into the registry on Windows 2000 at least).
500 * ega80woa.fon=ega80850.fon
501 * ega40woa.fon=ega40850.fon
502 * cga80woa.fon=cga80850.fon
503 * cga40woa.fon=cga40850.fon
506 /* These are all structures needed for the GSUB table */
508 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
509 #define TATEGAKI_LOWER_BOUND 0x02F1
525 GSUB_ScriptRecord ScriptRecord
[1];
531 } GSUB_LangSysRecord
;
536 GSUB_LangSysRecord LangSysRecord
[1];
540 WORD LookupOrder
; /* Reserved */
541 WORD ReqFeatureIndex
;
543 WORD FeatureIndex
[1];
549 } GSUB_FeatureRecord
;
553 GSUB_FeatureRecord FeatureRecord
[1];
557 WORD FeatureParams
; /* Reserved */
559 WORD LookupListIndex
[1];
578 } GSUB_CoverageFormat1
;
583 WORD StartCoverageIndex
;
589 GSUB_RangeRecord RangeRecord
[1];
590 } GSUB_CoverageFormat2
;
593 WORD SubstFormat
; /* = 1 */
596 } GSUB_SingleSubstFormat1
;
599 WORD SubstFormat
; /* = 2 */
603 }GSUB_SingleSubstFormat2
;
605 #ifdef HAVE_CARBON_CARBON_H
606 static char *find_cache_dir(void)
610 static char cached_path
[MAX_PATH
];
611 static const char *wine
= "/Wine", *fonts
= "/Fonts";
613 if(*cached_path
) return cached_path
;
615 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
618 WARN("can't create cached data folder\n");
621 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
624 WARN("can't create cached data path\n");
628 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
630 ERR("Could not create full path\n");
634 strcat(cached_path
, wine
);
636 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
638 WARN("Couldn't mkdir %s\n", cached_path
);
642 strcat(cached_path
, fonts
);
643 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
645 WARN("Couldn't mkdir %s\n", cached_path
);
652 /******************************************************************
655 * Extracts individual TrueType font files from a Mac suitcase font
656 * and saves them into the user's caches directory (see
658 * Returns a NULL terminated array of filenames.
660 * We do this because they are apps that try to read ttf files
661 * themselves and they don't like Mac suitcase files.
663 static char **expand_mac_font(const char *path
)
670 const char *filename
;
674 unsigned int size
, max_size
;
677 TRACE("path %s\n", path
);
679 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
682 WARN("failed to get ref\n");
686 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
689 TRACE("no data fork, so trying resource fork\n");
690 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
693 TRACE("unable to open resource fork\n");
700 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
703 CloseResFile(res_ref
);
707 out_dir
= find_cache_dir();
709 filename
= strrchr(path
, '/');
710 if(!filename
) filename
= path
;
713 /* output filename has the form out_dir/filename_%04x.ttf */
714 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
721 unsigned short *num_faces_ptr
, num_faces
, face
;
724 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
726 fond
= Get1IndResource(fond_res
, idx
);
728 TRACE("got fond resource %d\n", idx
);
731 fam_rec
= *(FamRec
**)fond
;
732 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
733 num_faces
= GET_BE_WORD(*num_faces_ptr
);
735 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
736 TRACE("num faces %04x\n", num_faces
);
737 for(face
= 0; face
< num_faces
; face
++, assoc
++)
740 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
741 unsigned short size
, font_id
;
744 size
= GET_BE_WORD(assoc
->fontSize
);
745 font_id
= GET_BE_WORD(assoc
->fontID
);
748 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
752 TRACE("trying to load sfnt id %04x\n", font_id
);
753 sfnt
= GetResource(sfnt_res
, font_id
);
756 TRACE("can't get sfnt resource %04x\n", font_id
);
760 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
765 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
767 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
768 if(fd
!= -1 || errno
== EEXIST
)
772 unsigned char *sfnt_data
;
775 sfnt_data
= *(unsigned char**)sfnt
;
776 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
780 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
783 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
785 ret
.array
[ret
.size
++] = output
;
789 WARN("unable to create %s\n", output
);
790 HeapFree(GetProcessHeap(), 0, output
);
793 ReleaseResource(sfnt
);
796 ReleaseResource(fond
);
799 CloseResFile(res_ref
);
804 #endif /* HAVE_CARBON_CARBON_H */
806 static inline BOOL
is_win9x(void)
808 return GetVersion() & 0x80000000;
811 This function builds an FT_Fixed from a double. It fails if the absolute
812 value of the float number is greater than 32768.
814 static inline FT_Fixed
FT_FixedFromFloat(double f
)
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
->from
.charset
&& 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
);
1030 /*****************************************************************
1031 * get_name_table_entry
1033 * Supply the platform, encoding, language and name ids in req
1034 * and if the name exists the function will fill in the string
1035 * and string_len members. The string is owned by FreeType so
1036 * don't free it. Returns TRUE if the name is found else FALSE.
1038 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1041 FT_UInt num_names
, name_index
;
1043 if(FT_IS_SFNT(ft_face
))
1045 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1047 for(name_index
= 0; name_index
< num_names
; name_index
++)
1049 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1051 if((name
.platform_id
== req
->platform_id
) &&
1052 (name
.encoding_id
== req
->encoding_id
) &&
1053 (name
.language_id
== req
->language_id
) &&
1054 (name
.name_id
== req
->name_id
))
1056 req
->string
= name
.string
;
1057 req
->string_len
= name
.string_len
;
1064 req
->string_len
= 0;
1068 static WCHAR
*get_familyname(FT_Face ft_face
)
1070 WCHAR
*family
= NULL
;
1073 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1074 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1075 name
.language_id
= GetUserDefaultLCID();
1076 name
.name_id
= TT_NAME_ID_FONT_FAMILY
;
1078 if(get_name_table_entry(ft_face
, &name
))
1082 /* String is not nul terminated and string_len is a byte length. */
1083 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1084 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1086 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1087 family
[i
] = GET_BE_WORD(*tmp
);
1090 TRACE("Got localised name %s\n", debugstr_w(family
));
1097 /*****************************************************************
1100 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1101 * of FreeType that don't export this function.
1104 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1109 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1110 if(pFT_Load_Sfnt_Table
)
1112 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1114 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1115 else /* Do it the hard way */
1117 TT_Face tt_face
= (TT_Face
) ft_face
;
1118 SFNT_Interface
*sfnt
;
1119 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1122 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1126 /* A field was added in the middle of the structure in 2.1.x */
1127 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1129 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1137 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1138 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1139 "Please upgrade your freetype library.\n");
1142 err
= FT_Err_Unimplemented_Feature
;
1148 static inline int TestStyles(DWORD flags
, DWORD styles
)
1150 return (flags
& styles
) == styles
;
1153 static int StyleOrdering(Face
*face
)
1155 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1157 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1159 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1161 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1164 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1165 debugstr_w(face
->family
->FamilyName
),
1166 debugstr_w(face
->StyleName
),
1172 /* Add a style of face to a font family using an ordering of the list such
1173 that regular fonts come before bold and italic, and single styles come
1174 before compound styles. */
1175 static void AddFaceToFamily(Face
*face
, Family
*family
)
1179 LIST_FOR_EACH( entry
, &family
->faces
)
1181 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1182 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1184 list_add_before( entry
, &face
->entry
);
1187 #define ADDFONT_EXTERNAL_FONT 0x01
1188 #define ADDFONT_FORCE_BITMAP 0x02
1189 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1193 TT_Header
*pHeader
= NULL
;
1194 WCHAR
*english_family
, *localised_family
, *StyleW
;
1198 struct list
*family_elem_ptr
, *face_elem_ptr
;
1200 FT_Long face_index
= 0, num_faces
;
1201 #ifdef HAVE_FREETYPE_FTWINFNT_H
1202 FT_WinFNT_HeaderRec winfnt_header
;
1204 int i
, bitmap_num
, internal_leading
;
1207 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1208 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1210 #ifdef HAVE_CARBON_CARBON_H
1211 if(file
&& !fake_family
)
1213 char **mac_list
= expand_mac_font(file
);
1216 BOOL had_one
= FALSE
;
1218 for(cursor
= mac_list
; *cursor
; cursor
++)
1221 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1222 HeapFree(GetProcessHeap(), 0, *cursor
);
1224 HeapFree(GetProcessHeap(), 0, mac_list
);
1229 #endif /* HAVE_CARBON_CARBON_H */
1232 char *family_name
= fake_family
;
1236 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1237 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1240 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1241 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1245 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1249 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*/
1250 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1251 pFT_Done_Face(ft_face
);
1255 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1256 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1257 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1258 pFT_Done_Face(ft_face
);
1262 if(FT_IS_SFNT(ft_face
))
1264 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1265 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1266 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1268 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1269 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1270 pFT_Done_Face(ft_face
);
1274 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1275 we don't want to load these. */
1276 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1280 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1282 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1283 pFT_Done_Face(ft_face
);
1289 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1290 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1291 pFT_Done_Face(ft_face
);
1295 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1297 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1298 pFT_Done_Face(ft_face
);
1304 localised_family
= get_familyname(ft_face
);
1305 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1307 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1308 HeapFree(GetProcessHeap(), 0, localised_family
);
1309 num_faces
= ft_face
->num_faces
;
1310 pFT_Done_Face(ft_face
);
1313 HeapFree(GetProcessHeap(), 0, localised_family
);
1317 family_name
= ft_face
->family_name
;
1321 My_FT_Bitmap_Size
*size
= NULL
;
1324 if(!FT_IS_SCALABLE(ft_face
))
1325 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1327 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1328 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1329 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1331 localised_family
= NULL
;
1333 localised_family
= get_familyname(ft_face
);
1334 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1335 HeapFree(GetProcessHeap(), 0, localised_family
);
1336 localised_family
= NULL
;
1341 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1342 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1343 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1348 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1349 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1350 list_init(&family
->faces
);
1351 list_add_tail(&font_list
, &family
->entry
);
1353 if(localised_family
) {
1354 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1355 subst
->from
.name
= strdupW(english_family
);
1356 subst
->from
.charset
= -1;
1357 subst
->to
.name
= strdupW(localised_family
);
1358 subst
->to
.charset
= -1;
1359 add_font_subst(&font_subst_list
, subst
, 0);
1362 HeapFree(GetProcessHeap(), 0, localised_family
);
1363 HeapFree(GetProcessHeap(), 0, english_family
);
1365 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1366 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1367 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1369 internal_leading
= 0;
1370 memset(&fs
, 0, sizeof(fs
));
1372 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1374 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1375 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1376 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1377 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1378 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1379 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1380 if(pOS2
->version
== 0) {
1383 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1384 fs
.fsCsb
[0] |= FS_LATIN1
;
1386 fs
.fsCsb
[0] |= FS_SYMBOL
;
1389 #ifdef HAVE_FREETYPE_FTWINFNT_H
1390 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1392 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1393 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1394 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1396 internal_leading
= winfnt_header
.internal_leading
;
1400 face_elem_ptr
= list_head(&family
->faces
);
1401 while(face_elem_ptr
) {
1402 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1403 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1404 if(!strcmpW(face
->StyleName
, StyleW
) &&
1405 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1406 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1407 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1408 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1411 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1412 HeapFree(GetProcessHeap(), 0, StyleW
);
1413 pFT_Done_Face(ft_face
);
1416 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1417 TRACE("Original font is newer so skipping this one\n");
1418 HeapFree(GetProcessHeap(), 0, StyleW
);
1419 pFT_Done_Face(ft_face
);
1422 TRACE("Replacing original with this one\n");
1423 list_remove(&face
->entry
);
1424 HeapFree(GetProcessHeap(), 0, face
->file
);
1425 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1426 HeapFree(GetProcessHeap(), 0, face
);
1431 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1432 face
->cached_enum_data
= NULL
;
1433 face
->StyleName
= StyleW
;
1436 face
->file
= strdupA(file
);
1437 face
->font_data_ptr
= NULL
;
1438 face
->font_data_size
= 0;
1443 face
->font_data_ptr
= font_data_ptr
;
1444 face
->font_data_size
= font_data_size
;
1446 face
->face_index
= face_index
;
1448 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1449 face
->ntmFlags
|= NTM_ITALIC
;
1450 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1451 face
->ntmFlags
|= NTM_BOLD
;
1452 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1453 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1454 face
->family
= family
;
1455 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1457 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1459 if(FT_IS_SCALABLE(ft_face
)) {
1460 memset(&face
->size
, 0, sizeof(face
->size
));
1461 face
->scalable
= TRUE
;
1463 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1464 size
->height
, size
->width
, size
->size
>> 6,
1465 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1466 face
->size
.height
= size
->height
;
1467 face
->size
.width
= size
->width
;
1468 face
->size
.size
= size
->size
;
1469 face
->size
.x_ppem
= size
->x_ppem
;
1470 face
->size
.y_ppem
= size
->y_ppem
;
1471 face
->size
.internal_leading
= internal_leading
;
1472 face
->scalable
= FALSE
;
1475 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1477 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1479 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1480 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1483 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1484 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1485 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1486 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1489 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1490 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1491 switch(ft_face
->charmaps
[i
]->encoding
) {
1492 case FT_ENCODING_UNICODE
:
1493 case FT_ENCODING_APPLE_ROMAN
:
1494 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1496 case FT_ENCODING_MS_SYMBOL
:
1497 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1505 if (!(face
->fs
.fsCsb
[0] & FS_SYMBOL
))
1506 have_installed_roman_font
= TRUE
;
1508 AddFaceToFamily(face
, family
);
1510 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1512 num_faces
= ft_face
->num_faces
;
1513 pFT_Done_Face(ft_face
);
1514 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1515 debugstr_w(StyleW
));
1516 } while(num_faces
> ++face_index
);
1520 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1522 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1525 static void DumpFontList(void)
1529 struct list
*family_elem_ptr
, *face_elem_ptr
;
1531 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1532 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1533 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1534 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1535 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1536 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1538 TRACE(" %d", face
->size
.height
);
1545 /***********************************************************
1546 * The replacement list is a way to map an entire font
1547 * family onto another family. For example adding
1549 * [HKCU\Software\Wine\Fonts\Replacements]
1550 * "Wingdings"="Winedings"
1552 * would enumerate the Winedings font both as Winedings and
1553 * Wingdings. However if a real Wingdings font is present the
1554 * replacement does not take place.
1557 static void LoadReplaceList(void)
1560 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1565 struct list
*family_elem_ptr
, *face_elem_ptr
;
1568 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1569 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1571 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1572 &valuelen
, &datalen
, NULL
, NULL
);
1574 valuelen
++; /* returned value doesn't include room for '\0' */
1575 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1576 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1580 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1581 &dlen
) == ERROR_SUCCESS
) {
1582 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1583 /* "NewName"="Oldname" */
1584 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1586 /* Find the old family and hence all of the font files
1588 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1589 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1590 if(!strcmpiW(family
->FamilyName
, data
)) {
1591 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1592 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1593 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1594 debugstr_w(face
->StyleName
), familyA
);
1595 /* Now add a new entry with the new family name */
1596 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1601 /* reset dlen and vlen */
1605 HeapFree(GetProcessHeap(), 0, data
);
1606 HeapFree(GetProcessHeap(), 0, value
);
1611 /*************************************************************
1614 static BOOL
init_system_links(void)
1616 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1617 'W','i','n','d','o','w','s',' ','N','T','\\',
1618 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1619 'S','y','s','t','e','m','L','i','n','k',0};
1622 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1623 WCHAR
*value
, *data
;
1624 WCHAR
*entry
, *next
;
1625 SYSTEM_LINKS
*font_link
, *system_font_link
;
1626 CHILD_FONT
*child_font
;
1627 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1628 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1629 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1635 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1637 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1638 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1639 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1640 val_len
= max_val
+ 1;
1641 data_len
= max_data
;
1643 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1645 TRACE("%s:\n", debugstr_w(value
));
1647 memset(&fs
, 0, sizeof(fs
));
1648 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1649 psub
= get_font_subst(&font_subst_list
, value
, -1);
1650 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1651 list_init(&font_link
->links
);
1652 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1655 CHILD_FONT
*child_font
;
1657 TRACE("\t%s\n", debugstr_w(entry
));
1659 next
= entry
+ strlenW(entry
) + 1;
1661 face_name
= strchrW(entry
, ',');
1665 while(isspaceW(*face_name
))
1668 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1670 face_name
= psub
->to
.name
;
1672 face
= find_face_from_filename(entry
, face_name
);
1675 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1679 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1680 child_font
->face
= face
;
1681 child_font
->font
= NULL
;
1682 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1683 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1684 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1685 list_add_tail(&font_link
->links
, &child_font
->entry
);
1687 family
= find_family_from_name(font_link
->font_name
);
1690 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1692 face
->fs_links
= fs
;
1695 list_add_tail(&system_links
, &font_link
->entry
);
1696 val_len
= max_val
+ 1;
1697 data_len
= max_data
;
1700 HeapFree(GetProcessHeap(), 0, value
);
1701 HeapFree(GetProcessHeap(), 0, data
);
1705 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1708 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1709 system_font_link
->font_name
= strdupW(System
);
1710 list_init(&system_font_link
->links
);
1712 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1715 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1716 child_font
->face
= face
;
1717 child_font
->font
= NULL
;
1718 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1719 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1721 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1723 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1725 CHILD_FONT
*font_link_entry
;
1726 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1728 CHILD_FONT
*new_child
;
1729 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1730 new_child
->face
= font_link_entry
->face
;
1731 new_child
->font
= NULL
;
1732 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1737 list_add_tail(&system_links
, &system_font_link
->entry
);
1741 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1744 struct dirent
*dent
;
1745 char path
[MAX_PATH
];
1747 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1749 dir
= opendir(dirname
);
1751 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1754 while((dent
= readdir(dir
)) != NULL
) {
1755 struct stat statbuf
;
1757 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1760 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1762 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1764 if(stat(path
, &statbuf
) == -1)
1766 WARN("Can't stat %s\n", debugstr_a(path
));
1769 if(S_ISDIR(statbuf
.st_mode
))
1770 ReadFontDir(path
, external_fonts
);
1772 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1778 static void load_fontconfig_fonts(void)
1780 #ifdef SONAME_LIBFONTCONFIG
1781 void *fc_handle
= NULL
;
1790 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1792 TRACE("Wine cannot find the fontconfig library (%s).\n",
1793 SONAME_LIBFONTCONFIG
);
1796 #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;}
1797 LOAD_FUNCPTR(FcConfigGetCurrent
);
1798 LOAD_FUNCPTR(FcFontList
);
1799 LOAD_FUNCPTR(FcFontSetDestroy
);
1800 LOAD_FUNCPTR(FcInit
);
1801 LOAD_FUNCPTR(FcObjectSetAdd
);
1802 LOAD_FUNCPTR(FcObjectSetCreate
);
1803 LOAD_FUNCPTR(FcObjectSetDestroy
);
1804 LOAD_FUNCPTR(FcPatternCreate
);
1805 LOAD_FUNCPTR(FcPatternDestroy
);
1806 LOAD_FUNCPTR(FcPatternGetBool
);
1807 LOAD_FUNCPTR(FcPatternGetString
);
1810 if(!pFcInit()) return;
1812 config
= pFcConfigGetCurrent();
1813 pat
= pFcPatternCreate();
1814 os
= pFcObjectSetCreate();
1815 pFcObjectSetAdd(os
, FC_FILE
);
1816 pFcObjectSetAdd(os
, FC_SCALABLE
);
1817 fontset
= pFcFontList(config
, pat
, os
);
1818 if(!fontset
) return;
1819 for(i
= 0; i
< fontset
->nfont
; i
++) {
1822 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1824 TRACE("fontconfig: %s\n", file
);
1826 /* We're just interested in OT/TT fonts for now, so this hack just
1827 picks up the scalable fonts without extensions .pf[ab] to save time
1828 loading every other font */
1830 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1832 TRACE("not scalable\n");
1836 len
= strlen( file
);
1837 if(len
< 4) continue;
1838 ext
= &file
[ len
- 3 ];
1839 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1840 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1842 pFcFontSetDestroy(fontset
);
1843 pFcObjectSetDestroy(os
);
1844 pFcPatternDestroy(pat
);
1850 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1853 const char *data_dir
= wine_get_data_dir();
1855 if (!data_dir
) data_dir
= wine_get_build_dir();
1862 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1864 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1866 strcpy(unix_name
, data_dir
);
1867 strcat(unix_name
, "/fonts/");
1869 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1871 EnterCriticalSection( &freetype_cs
);
1872 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1873 LeaveCriticalSection( &freetype_cs
);
1874 HeapFree(GetProcessHeap(), 0, unix_name
);
1879 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1881 static const WCHAR slashW
[] = {'\\','\0'};
1883 WCHAR windowsdir
[MAX_PATH
];
1886 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1887 strcatW(windowsdir
, fontsW
);
1888 strcatW(windowsdir
, slashW
);
1889 strcatW(windowsdir
, file
);
1890 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1891 EnterCriticalSection( &freetype_cs
);
1892 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1893 LeaveCriticalSection( &freetype_cs
);
1894 HeapFree(GetProcessHeap(), 0, unixname
);
1899 static void load_system_fonts(void)
1902 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1903 const WCHAR
* const *value
;
1905 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1908 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1909 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1910 strcatW(windowsdir
, fontsW
);
1911 for(value
= SystemFontValues
; *value
; value
++) {
1912 dlen
= sizeof(data
);
1913 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1917 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1918 if((unixname
= wine_get_unix_file_name(pathW
))) {
1919 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1920 HeapFree(GetProcessHeap(), 0, unixname
);
1923 load_font_from_data_dir(data
);
1930 /*************************************************************
1932 * This adds registry entries for any externally loaded fonts
1933 * (fonts from fontconfig or FontDirs). It also deletes entries
1934 * of no longer existing fonts.
1937 static void update_reg_entries(void)
1939 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1944 struct list
*family_elem_ptr
, *face_elem_ptr
;
1946 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1947 static const WCHAR spaceW
[] = {' ', '\0'};
1950 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1951 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1952 ERR("Can't create Windows font reg key\n");
1956 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1957 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1958 ERR("Can't create Windows font reg key\n");
1962 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1963 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
1964 ERR("Can't create external font reg key\n");
1968 /* enumerate the fonts and add external ones to the two keys */
1970 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1971 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1972 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1973 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1974 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1975 if(!face
->external
) continue;
1977 if (!(face
->ntmFlags
& NTM_REGULAR
))
1978 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1979 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1980 strcpyW(valueW
, family
->FamilyName
);
1981 if(len
!= len_fam
) {
1982 strcatW(valueW
, spaceW
);
1983 strcatW(valueW
, face
->StyleName
);
1985 strcatW(valueW
, TrueType
);
1987 file
= wine_get_dos_file_name(face
->file
);
1989 len
= strlenW(file
) + 1;
1992 if((path
= strrchr(face
->file
, '/')) == NULL
)
1996 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1998 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1999 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2001 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2002 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2003 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2005 HeapFree(GetProcessHeap(), 0, file
);
2006 HeapFree(GetProcessHeap(), 0, valueW
);
2010 if(external_key
) RegCloseKey(external_key
);
2011 if(win9x_key
) RegCloseKey(win9x_key
);
2012 if(winnt_key
) RegCloseKey(winnt_key
);
2016 static void delete_external_font_keys(void)
2018 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2019 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2023 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2024 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2025 ERR("Can't create Windows font reg key\n");
2029 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2030 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2031 ERR("Can't create Windows font reg key\n");
2035 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2036 ERR("Can't create external font reg key\n");
2040 /* Delete all external fonts added last time */
2042 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2043 &valuelen
, &datalen
, NULL
, NULL
);
2044 valuelen
++; /* returned value doesn't include room for '\0' */
2045 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2046 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2048 dlen
= datalen
* sizeof(WCHAR
);
2051 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2052 &dlen
) == ERROR_SUCCESS
) {
2054 RegDeleteValueW(winnt_key
, valueW
);
2055 RegDeleteValueW(win9x_key
, valueW
);
2056 /* reset dlen and vlen */
2060 HeapFree(GetProcessHeap(), 0, data
);
2061 HeapFree(GetProcessHeap(), 0, valueW
);
2063 /* Delete the old external fonts key */
2064 RegCloseKey(external_key
);
2065 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2068 if(win9x_key
) RegCloseKey(win9x_key
);
2069 if(winnt_key
) RegCloseKey(winnt_key
);
2072 /*************************************************************
2073 * WineEngAddFontResourceEx
2076 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2079 if (ft_handle
) /* do it only if we have freetype up and running */
2084 FIXME("Ignoring flags %x\n", flags
);
2086 if((unixname
= wine_get_unix_file_name(file
)))
2088 EnterCriticalSection( &freetype_cs
);
2089 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2090 LeaveCriticalSection( &freetype_cs
);
2091 HeapFree(GetProcessHeap(), 0, unixname
);
2093 if (!ret
&& !strchrW(file
, '\\')) {
2094 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2095 ret
= load_font_from_winfonts_dir(file
);
2097 /* Try in datadir/fonts (or builddir/fonts),
2098 * needed for Magic the Gathering Online
2100 ret
= load_font_from_data_dir(file
);
2107 /*************************************************************
2108 * WineEngAddFontMemResourceEx
2111 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2113 if (ft_handle
) /* do it only if we have freetype up and running */
2115 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2117 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2118 memcpy(pFontCopy
, pbFont
, cbFont
);
2120 EnterCriticalSection( &freetype_cs
);
2121 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2122 LeaveCriticalSection( &freetype_cs
);
2126 TRACE("AddFontToList failed\n");
2127 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2130 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2131 * For now return something unique but quite random
2133 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2134 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2141 /*************************************************************
2142 * WineEngRemoveFontResourceEx
2145 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2151 static const struct nls_update_font_list
2153 UINT ansi_cp
, oem_cp
;
2154 const char *oem
, *fixed
, *system
;
2155 const char *courier
, *serif
, *small
, *sserif
;
2156 /* these are for font substitutes */
2157 const char *shelldlg
, *tmsrmn
;
2158 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2162 const char *from
, *to
;
2163 } arial_0
, courier_new_0
, times_new_roman_0
;
2164 } nls_update_font_list
[] =
2166 /* Latin 1 (United States) */
2167 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2168 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2169 "Tahoma","Times New Roman",
2170 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2173 /* Latin 1 (Multilingual) */
2174 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2175 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2176 "Tahoma","Times New Roman", /* FIXME unverified */
2177 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2180 /* Eastern Europe */
2181 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2182 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2183 "Tahoma","Times New Roman", /* FIXME unverified */
2184 "Fixedsys,238", "System,238",
2185 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2186 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2187 { "Arial CE,0", "Arial,238" },
2188 { "Courier New CE,0", "Courier New,238" },
2189 { "Times New Roman CE,0", "Times New Roman,238" }
2192 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2193 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2194 "Tahoma","Times New Roman", /* FIXME unverified */
2195 "Fixedsys,204", "System,204",
2196 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2197 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2198 { "Arial Cyr,0", "Arial,204" },
2199 { "Courier New Cyr,0", "Courier New,204" },
2200 { "Times New Roman Cyr,0", "Times New Roman,204" }
2203 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2204 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 "Fixedsys,161", "System,161",
2207 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2208 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2209 { "Arial Greek,0", "Arial,161" },
2210 { "Courier New Greek,0", "Courier New,161" },
2211 { "Times New Roman Greek,0", "Times New Roman,161" }
2214 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2215 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,162", "System,162",
2218 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2219 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2220 { "Arial Tur,0", "Arial,162" },
2221 { "Courier New Tur,0", "Courier New,162" },
2222 { "Times New Roman Tur,0", "Times New Roman,162" }
2225 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2226 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 "Fixedsys,177", "System,177",
2229 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2230 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2234 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2235 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2236 "Tahoma","Times New Roman", /* FIXME unverified */
2237 "Fixedsys,178", "System,178",
2238 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2239 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2243 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2244 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2245 "Tahoma","Times New Roman", /* FIXME unverified */
2246 "Fixedsys,186", "System,186",
2247 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2248 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2249 { "Arial Baltic,0", "Arial,186" },
2250 { "Courier New Baltic,0", "Courier New,186" },
2251 { "Times New Roman Baltic,0", "Times New Roman,186" }
2254 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2255 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2256 "Tahoma","Times New Roman", /* FIXME unverified */
2257 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2261 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2262 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2263 "Tahoma","Times New Roman", /* FIXME unverified */
2264 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2268 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2269 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2270 "MS UI Gothic","MS Serif",
2271 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2274 /* Chinese Simplified */
2275 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2276 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2277 "Tahoma", "Times New Roman", /* FIXME unverified */
2278 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2282 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2283 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2285 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2288 /* Chinese Traditional */
2289 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2290 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2291 "PMingLiU", "MingLiU",
2292 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2297 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2299 return ( ansi_cp
== 932 /* CP932 for Japanese */
2300 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2301 || ansi_cp
== 949 /* CP949 for Korean */
2302 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2305 static inline HKEY
create_fonts_NT_registry_key(void)
2309 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2310 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2314 static inline HKEY
create_fonts_9x_registry_key(void)
2318 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2319 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2323 static inline HKEY
create_config_fonts_registry_key(void)
2327 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2328 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2332 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2334 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2335 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2336 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2337 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2340 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2343 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2345 RegDeleteValueA(hkey
, name
);
2348 static void update_font_info(void)
2350 char buf
[40], cpbuf
[40];
2353 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2356 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2359 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2360 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2361 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2362 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2363 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2365 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2366 if (is_dbcs_ansi_cp(ansi_cp
))
2367 use_default_fallback
= TRUE
;
2370 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2372 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2377 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2379 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2381 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2384 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2388 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2389 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2391 hkey
= create_config_fonts_registry_key();
2392 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2393 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2394 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2397 hkey
= create_fonts_NT_registry_key();
2398 add_font_list(hkey
, &nls_update_font_list
[i
]);
2401 hkey
= create_fonts_9x_registry_key();
2402 add_font_list(hkey
, &nls_update_font_list
[i
]);
2405 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2407 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2408 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2409 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2410 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2412 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2413 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2414 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2415 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2416 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2417 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2418 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2419 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2421 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2422 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2423 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2431 /* Delete the FontSubstitutes from other locales */
2432 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2434 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2435 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2436 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2442 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2446 static BOOL
init_freetype(void)
2448 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2451 "Wine cannot find the FreeType font library. To enable Wine to\n"
2452 "use TrueType fonts please install a version of FreeType greater than\n"
2453 "or equal to 2.0.5.\n"
2454 "http://www.freetype.org\n");
2458 #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;}
2460 LOAD_FUNCPTR(FT_Vector_Unit
)
2461 LOAD_FUNCPTR(FT_Done_Face
)
2462 LOAD_FUNCPTR(FT_Get_Char_Index
)
2463 LOAD_FUNCPTR(FT_Get_Module
)
2464 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2465 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2466 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2467 LOAD_FUNCPTR(FT_Init_FreeType
)
2468 LOAD_FUNCPTR(FT_Load_Glyph
)
2469 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2470 #ifndef FT_MULFIX_INLINED
2471 LOAD_FUNCPTR(FT_MulFix
)
2473 LOAD_FUNCPTR(FT_New_Face
)
2474 LOAD_FUNCPTR(FT_New_Memory_Face
)
2475 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2476 LOAD_FUNCPTR(FT_Outline_Transform
)
2477 LOAD_FUNCPTR(FT_Outline_Translate
)
2478 LOAD_FUNCPTR(FT_Select_Charmap
)
2479 LOAD_FUNCPTR(FT_Set_Charmap
)
2480 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2481 LOAD_FUNCPTR(FT_Vector_Transform
)
2484 /* Don't warn if these ones are missing */
2485 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2486 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2487 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2488 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2489 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2490 #ifdef HAVE_FREETYPE_FTWINFNT_H
2491 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2493 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2494 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2495 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2496 <= 2.0.3 has FT_Sqrt64 */
2500 if(pFT_Init_FreeType(&library
) != 0) {
2501 ERR("Can't init FreeType library\n");
2502 wine_dlclose(ft_handle
, NULL
, 0);
2506 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2507 if (pFT_Library_Version
)
2508 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2510 if (FT_Version
.major
<=0)
2516 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2517 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2518 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2519 ((FT_Version
.patch
) & 0x0000ff);
2525 "Wine cannot find certain functions that it needs inside the FreeType\n"
2526 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2527 "FreeType to at least version 2.0.5.\n"
2528 "http://www.freetype.org\n");
2529 wine_dlclose(ft_handle
, NULL
, 0);
2534 /*************************************************************
2537 * Initialize FreeType library and create a list of available faces
2539 BOOL
WineEngInit(void)
2541 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2542 static const WCHAR pathW
[] = {'P','a','t','h',0};
2544 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2546 WCHAR windowsdir
[MAX_PATH
];
2549 const char *data_dir
;
2553 /* update locale dependent font info in registry */
2556 if(!init_freetype()) return FALSE
;
2558 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2559 ERR("Failed to create font mutex\n");
2562 WaitForSingleObject(font_mutex
, INFINITE
);
2564 delete_external_font_keys();
2566 /* load the system bitmap fonts */
2567 load_system_fonts();
2569 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2570 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2571 strcatW(windowsdir
, fontsW
);
2572 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2574 ReadFontDir(unixname
, FALSE
);
2575 HeapFree(GetProcessHeap(), 0, unixname
);
2578 /* load the system truetype fonts */
2579 data_dir
= wine_get_data_dir();
2580 if (!data_dir
) data_dir
= wine_get_build_dir();
2581 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2582 strcpy(unixname
, data_dir
);
2583 strcat(unixname
, "/fonts/");
2584 ReadFontDir(unixname
, TRUE
);
2585 HeapFree(GetProcessHeap(), 0, unixname
);
2588 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2589 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2590 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2592 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2593 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2594 &hkey
) == ERROR_SUCCESS
) {
2596 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2597 &valuelen
, &datalen
, NULL
, NULL
);
2599 valuelen
++; /* returned value doesn't include room for '\0' */
2600 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2601 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2604 dlen
= datalen
* sizeof(WCHAR
);
2606 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2607 &dlen
) == ERROR_SUCCESS
) {
2608 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2610 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2612 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2613 HeapFree(GetProcessHeap(), 0, unixname
);
2616 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2618 WCHAR pathW
[MAX_PATH
];
2619 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2622 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2623 if((unixname
= wine_get_unix_file_name(pathW
)))
2625 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2626 HeapFree(GetProcessHeap(), 0, unixname
);
2629 load_font_from_data_dir(data
);
2631 /* reset dlen and vlen */
2636 HeapFree(GetProcessHeap(), 0, data
);
2637 HeapFree(GetProcessHeap(), 0, valueW
);
2641 load_fontconfig_fonts();
2643 /* then look in any directories that we've specified in the config file */
2644 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2645 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2651 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2653 len
+= sizeof(WCHAR
);
2654 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2655 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2657 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2658 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2659 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2660 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2664 LPSTR next
= strchr( ptr
, ':' );
2665 if (next
) *next
++ = 0;
2666 ReadFontDir( ptr
, TRUE
);
2669 HeapFree( GetProcessHeap(), 0, valueA
);
2671 HeapFree( GetProcessHeap(), 0, valueW
);
2680 update_reg_entries();
2682 init_system_links();
2684 ReleaseMutex(font_mutex
);
2689 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2692 TT_HoriHeader
*pHori
;
2696 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2697 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2699 if(height
== 0) height
= 16;
2701 /* Calc. height of EM square:
2703 * For +ve lfHeight we have
2704 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2705 * Re-arranging gives:
2706 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2708 * For -ve lfHeight we have
2710 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2711 * with il = winAscent + winDescent - units_per_em]
2716 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2717 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2718 pHori
->Ascender
- pHori
->Descender
);
2720 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2721 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2729 static struct font_mapping
*map_font_file( const char *name
)
2731 struct font_mapping
*mapping
;
2735 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2736 if (fstat( fd
, &st
) == -1) goto error
;
2738 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2740 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2742 mapping
->refcount
++;
2747 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2750 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2753 if (mapping
->data
== MAP_FAILED
)
2755 HeapFree( GetProcessHeap(), 0, mapping
);
2758 mapping
->refcount
= 1;
2759 mapping
->dev
= st
.st_dev
;
2760 mapping
->ino
= st
.st_ino
;
2761 mapping
->size
= st
.st_size
;
2762 list_add_tail( &mappings_list
, &mapping
->entry
);
2770 static void unmap_font_file( struct font_mapping
*mapping
)
2772 if (!--mapping
->refcount
)
2774 list_remove( &mapping
->entry
);
2775 munmap( mapping
->data
, mapping
->size
);
2776 HeapFree( GetProcessHeap(), 0, mapping
);
2780 static LONG
load_VDMX(GdiFont
*, LONG
);
2782 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2789 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2793 if (!(font
->mapping
= map_font_file( face
->file
)))
2795 WARN("failed to map %s\n", debugstr_a(face
->file
));
2798 data_ptr
= font
->mapping
->data
;
2799 data_size
= font
->mapping
->size
;
2803 data_ptr
= face
->font_data_ptr
;
2804 data_size
= face
->font_data_size
;
2807 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2809 ERR("FT_New_Face rets %d\n", err
);
2813 /* set it here, as load_VDMX needs it */
2814 font
->ft_face
= ft_face
;
2816 if(FT_IS_SCALABLE(ft_face
)) {
2817 /* load the VDMX table if we have one */
2818 font
->ppem
= load_VDMX(font
, height
);
2820 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2821 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
2823 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2824 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2826 font
->ppem
= height
;
2827 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2828 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2834 static int get_nearest_charset(Face
*face
, int *cp
)
2836 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2837 a single face with the requested charset. The idea is to check if
2838 the selected font supports the current ANSI codepage, if it does
2839 return the corresponding charset, else return the first charset */
2842 int acp
= GetACP(), i
;
2846 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2847 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2848 return csi
.ciCharset
;
2850 for(i
= 0; i
< 32; i
++) {
2852 if(face
->fs
.fsCsb
[0] & fs0
) {
2853 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2855 return csi
.ciCharset
;
2858 FIXME("TCI failing on %x\n", fs0
);
2862 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2863 face
->fs
.fsCsb
[0], face
->file
);
2865 return DEFAULT_CHARSET
;
2868 static GdiFont
*alloc_font(void)
2870 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2872 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2873 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2875 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2876 ret
->total_kern_pairs
= (DWORD
)-1;
2877 ret
->kern_pairs
= NULL
;
2878 list_init(&ret
->hfontlist
);
2879 list_init(&ret
->child_fonts
);
2883 static void free_font(GdiFont
*font
)
2885 struct list
*cursor
, *cursor2
;
2888 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2890 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2891 struct list
*first_hfont
;
2892 HFONTLIST
*hfontlist
;
2893 list_remove(cursor
);
2896 first_hfont
= list_head(&child
->font
->hfontlist
);
2897 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2898 DeleteObject(hfontlist
->hfont
);
2899 HeapFree(GetProcessHeap(), 0, hfontlist
);
2900 free_font(child
->font
);
2902 HeapFree(GetProcessHeap(), 0, child
);
2905 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2906 if (font
->mapping
) unmap_font_file( font
->mapping
);
2907 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2908 HeapFree(GetProcessHeap(), 0, font
->potm
);
2909 HeapFree(GetProcessHeap(), 0, font
->name
);
2910 for (i
= 0; i
< font
->gmsize
; i
++)
2911 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2912 HeapFree(GetProcessHeap(), 0, font
->gm
);
2913 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
2914 HeapFree(GetProcessHeap(), 0, font
);
2918 /*************************************************************
2921 * load the vdmx entry for the specified height
2924 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2925 ( ( (FT_ULong)_x4 << 24 ) | \
2926 ( (FT_ULong)_x3 << 16 ) | \
2927 ( (FT_ULong)_x2 << 8 ) | \
2930 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2945 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2949 BYTE devXRatio
, devYRatio
;
2950 USHORT numRecs
, numRatios
;
2951 DWORD result
, offset
= -1;
2955 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2957 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2960 /* FIXME: need the real device aspect ratio */
2964 numRecs
= GET_BE_WORD(hdr
[1]);
2965 numRatios
= GET_BE_WORD(hdr
[2]);
2967 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2968 for(i
= 0; i
< numRatios
; i
++) {
2971 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2972 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2975 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2977 if((ratio
.xRatio
== 0 &&
2978 ratio
.yStartRatio
== 0 &&
2979 ratio
.yEndRatio
== 0) ||
2980 (devXRatio
== ratio
.xRatio
&&
2981 devYRatio
>= ratio
.yStartRatio
&&
2982 devYRatio
<= ratio
.yEndRatio
))
2984 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2985 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2986 offset
= GET_BE_WORD(tmp
);
2992 FIXME("No suitable ratio found\n");
2996 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2998 BYTE startsz
, endsz
;
3001 recs
= GET_BE_WORD(group
.recs
);
3002 startsz
= group
.startsz
;
3003 endsz
= group
.endsz
;
3005 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3007 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3008 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3009 if(result
== GDI_ERROR
) {
3010 FIXME("Failed to retrieve vTable\n");
3015 for(i
= 0; i
< recs
; i
++) {
3016 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3017 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3018 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3020 if(yMax
+ -yMin
== height
) {
3023 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3026 if(yMax
+ -yMin
> height
) {
3029 goto end
; /* failed */
3031 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3032 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3033 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3034 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3040 TRACE("ppem not found for height %d\n", height
);
3044 if(ppem
< startsz
|| ppem
> endsz
)
3047 for(i
= 0; i
< recs
; i
++) {
3049 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
3051 if(yPelHeight
> ppem
)
3054 if(yPelHeight
== ppem
) {
3055 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3056 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3057 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
3063 HeapFree(GetProcessHeap(), 0, vTable
);
3069 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3071 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3072 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3073 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3074 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3075 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3078 static void calc_hash(FONT_DESC
*pfd
)
3080 DWORD hash
= 0, *ptr
, two_chars
;
3084 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3086 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3088 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3090 pwc
= (WCHAR
*)&two_chars
;
3092 *pwc
= toupperW(*pwc
);
3094 *pwc
= toupperW(*pwc
);
3098 hash
^= !pfd
->can_use_bitmap
;
3103 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3108 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3112 fd
.can_use_bitmap
= can_use_bitmap
;
3115 /* try the in-use list */
3116 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3117 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3118 if(!fontcmp(ret
, &fd
)) {
3119 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3120 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3121 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3122 if(hflist
->hfont
== hfont
)
3125 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3126 hflist
->hfont
= hfont
;
3127 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3132 /* then the unused list */
3133 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3134 while(font_elem_ptr
) {
3135 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3136 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3137 if(!fontcmp(ret
, &fd
)) {
3138 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3139 assert(list_empty(&ret
->hfontlist
));
3140 TRACE("Found %p in unused list\n", ret
);
3141 list_remove(&ret
->entry
);
3142 list_add_head(&gdi_font_list
, &ret
->entry
);
3143 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3144 hflist
->hfont
= hfont
;
3145 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3152 static void add_to_cache(GdiFont
*font
)
3154 static DWORD cache_num
= 1;
3156 font
->cache_num
= cache_num
++;
3157 list_add_head(&gdi_font_list
, &font
->entry
);
3160 /*************************************************************
3161 * create_child_font_list
3163 static BOOL
create_child_font_list(GdiFont
*font
)
3166 SYSTEM_LINKS
*font_link
;
3167 CHILD_FONT
*font_link_entry
, *new_child
;
3169 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3171 if(!strcmpW(font_link
->font_name
, font
->name
))
3173 TRACE("found entry in system list\n");
3174 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3176 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3177 new_child
->face
= font_link_entry
->face
;
3178 new_child
->font
= NULL
;
3179 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3180 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3187 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3188 * Sans Serif. This is how asian windows get default fallbacks for fonts
3190 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3191 font
->charset
!= OEM_CHARSET
&&
3192 strcmpW(font
->name
,szDefaultFallbackLink
) != 0)
3193 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3195 if(!strcmpW(font_link
->font_name
,szDefaultFallbackLink
))
3197 TRACE("found entry in default fallback list\n");
3198 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3200 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3201 new_child
->face
= font_link_entry
->face
;
3202 new_child
->font
= NULL
;
3203 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3204 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3214 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3216 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3218 if (pFT_Set_Charmap
)
3221 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3223 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3225 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3227 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3229 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3230 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3232 switch (ft_face
->charmaps
[i
]->platform_id
)
3235 cmap_def
= ft_face
->charmaps
[i
];
3237 case 0: /* Apple Unicode */
3238 cmap0
= ft_face
->charmaps
[i
];
3240 case 1: /* Macintosh */
3241 cmap1
= ft_face
->charmaps
[i
];
3244 cmap2
= ft_face
->charmaps
[i
];
3246 case 3: /* Microsoft */
3247 cmap3
= ft_face
->charmaps
[i
];
3252 if (cmap3
) /* prefer Microsoft cmap table */
3253 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3255 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3257 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3259 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3261 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3263 return ft_err
== FT_Err_Ok
;
3266 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3269 /*************************************************************
3270 * WineEngCreateFontInstance
3273 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3276 Face
*face
, *best
, *best_bitmap
;
3277 Family
*family
, *last_resort_family
;
3278 struct list
*family_elem_ptr
, *face_elem_ptr
;
3279 INT height
, width
= 0;
3280 unsigned int score
= 0, new_score
;
3281 signed int diff
= 0, newdiff
;
3282 BOOL bd
, it
, can_use_bitmap
;
3287 FontSubst
*psub
= NULL
;
3289 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3290 lf
.lfWidth
= abs(lf
.lfWidth
);
3292 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3294 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3295 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3296 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3299 if(dc
->GraphicsMode
== GM_ADVANCED
)
3300 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3303 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3304 font scaling abilities. */
3305 dcmat
.eM11
= dcmat
.eM22
= fabs(dc
->xformWorld2Vport
.eM22
);
3306 dcmat
.eM21
= dcmat
.eM12
= 0;
3309 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3310 dcmat
.eM21
, dcmat
.eM22
);
3312 EnterCriticalSection( &freetype_cs
);
3314 /* check the cache first */
3315 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3316 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3317 LeaveCriticalSection( &freetype_cs
);
3321 TRACE("not in cache\n");
3322 if(list_empty(&font_list
)) /* No fonts installed */
3324 TRACE("No fonts installed\n");
3325 LeaveCriticalSection( &freetype_cs
);
3328 if(!have_installed_roman_font
)
3330 TRACE("No roman font installed\n");
3331 LeaveCriticalSection( &freetype_cs
);
3337 ret
->font_desc
.matrix
= dcmat
;
3338 ret
->font_desc
.lf
= lf
;
3339 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3340 calc_hash(&ret
->font_desc
);
3341 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3342 hflist
->hfont
= hfont
;
3343 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3345 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3346 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3347 original value lfCharSet. Note this is a special case for
3348 Symbol and doesn't happen at least for "Wingdings*" */
3350 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3351 lf
.lfCharSet
= SYMBOL_CHARSET
;
3353 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3354 switch(lf
.lfCharSet
) {
3355 case DEFAULT_CHARSET
:
3356 csi
.fs
.fsCsb
[0] = 0;
3359 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3360 csi
.fs
.fsCsb
[0] = 0;
3366 if(lf
.lfFaceName
[0] != '\0') {
3367 SYSTEM_LINKS
*font_link
;
3368 CHILD_FONT
*font_link_entry
;
3369 LPWSTR FaceName
= lf
.lfFaceName
;
3372 * Check for a leading '@' this signals that the font is being
3373 * requested in tategaki mode (vertical writing substitution) but
3374 * does not affect the fontface that is to be selected.
3376 if (lf
.lfFaceName
[0]=='@')
3377 FaceName
= &lf
.lfFaceName
[1];
3379 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3382 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
3383 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
3384 if (psub
->to
.charset
!= -1)
3385 lf
.lfCharSet
= psub
->to
.charset
;
3388 /* We want a match on name and charset or just name if
3389 charset was DEFAULT_CHARSET. If the latter then
3390 we fixup the returned charset later in get_nearest_charset
3391 where we'll either use the charset of the current ansi codepage
3392 or if that's unavailable the first charset that the font supports.
3394 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3395 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3396 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
3397 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
3399 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3400 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3401 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3402 if(face
->scalable
|| can_use_bitmap
)
3409 * Try check the SystemLink list first for a replacement font.
3410 * We may find good replacements there.
3412 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3414 if(!strcmpiW(font_link
->font_name
, FaceName
))
3416 TRACE("found entry in system list\n");
3417 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3419 face
= font_link_entry
->face
;
3420 family
= face
->family
;
3421 if(csi
.fs
.fsCsb
[0] &
3422 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3424 if(face
->scalable
|| can_use_bitmap
)
3432 psub
= NULL
; /* substitution is no more relevant */
3434 /* If requested charset was DEFAULT_CHARSET then try using charset
3435 corresponding to the current ansi codepage */
3436 if (!csi
.fs
.fsCsb
[0])
3439 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3440 FIXME("TCI failed on codepage %d\n", acp
);
3441 csi
.fs
.fsCsb
[0] = 0;
3443 lf
.lfCharSet
= csi
.ciCharset
;
3446 /* Face families are in the top 4 bits of lfPitchAndFamily,
3447 so mask with 0xF0 before testing */
3449 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3450 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3451 strcpyW(lf
.lfFaceName
, defFixed
);
3452 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3453 strcpyW(lf
.lfFaceName
, defSerif
);
3454 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3455 strcpyW(lf
.lfFaceName
, defSans
);
3457 strcpyW(lf
.lfFaceName
, defSans
);
3458 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3459 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3460 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3461 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3462 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3463 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3464 if(face
->scalable
|| can_use_bitmap
)
3470 last_resort_family
= NULL
;
3471 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3472 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3473 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3474 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3475 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3478 if(can_use_bitmap
&& !last_resort_family
)
3479 last_resort_family
= family
;
3484 if(last_resort_family
) {
3485 family
= last_resort_family
;
3486 csi
.fs
.fsCsb
[0] = 0;
3490 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3491 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3492 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3493 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3494 if(face
->scalable
) {
3495 csi
.fs
.fsCsb
[0] = 0;
3496 WARN("just using first face for now\n");
3499 if(can_use_bitmap
&& !last_resort_family
)
3500 last_resort_family
= family
;
3503 if(!last_resort_family
) {
3504 FIXME("can't find a single appropriate font - bailing\n");
3506 LeaveCriticalSection( &freetype_cs
);
3510 WARN("could only find a bitmap font - this will probably look awful!\n");
3511 family
= last_resort_family
;
3512 csi
.fs
.fsCsb
[0] = 0;
3515 it
= lf
.lfItalic
? 1 : 0;
3516 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3518 height
= lf
.lfHeight
;
3520 face
= best
= best_bitmap
= NULL
;
3521 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3523 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3527 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3528 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3529 new_score
= (italic
^ it
) + (bold
^ bd
);
3530 if(!best
|| new_score
<= score
)
3532 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3533 italic
, bold
, it
, bd
);
3536 if(best
->scalable
&& score
== 0) break;
3540 newdiff
= height
- (signed int)(best
->size
.height
);
3542 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3543 if(!best_bitmap
|| new_score
< score
||
3544 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3546 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3549 if(score
== 0 && diff
== 0) break;
3556 face
= best
->scalable
? best
: best_bitmap
;
3557 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3558 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3562 if(csi
.fs
.fsCsb
[0]) {
3563 ret
->charset
= lf
.lfCharSet
;
3564 ret
->codepage
= csi
.ciACP
;
3567 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3569 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3570 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3572 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3574 if(!face
->scalable
) {
3575 /* Windows uses integer scaling factors for bitmap fonts */
3576 INT scale
, scaled_height
;
3578 /* FIXME: rotation of bitmap fonts is ignored */
3579 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
3581 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
3582 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3584 if (height
!= 0) height
= diff
;
3585 height
+= face
->size
.height
;
3587 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3588 scaled_height
= scale
* face
->size
.height
;
3589 /* XP allows not more than 10% deviation */
3590 if (scale
> 1 && scaled_height
- height
> scaled_height
/ 10) scale
--;
3591 ret
->scale_y
= scale
;
3593 width
= face
->size
.x_ppem
>> 6;
3594 height
= face
->size
.y_ppem
>> 6;
3598 TRACE("font scale y: %f\n", ret
->scale_y
);
3600 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3605 LeaveCriticalSection( &freetype_cs
);
3609 ret
->ntmFlags
= face
->ntmFlags
;
3611 if (ret
->charset
== SYMBOL_CHARSET
&&
3612 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3615 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3619 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3622 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3623 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
3624 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3625 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3626 create_child_font_list(ret
);
3628 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3630 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3631 if (length
!= GDI_ERROR
)
3633 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3634 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3635 TRACE("Loaded GSUB table of %i bytes\n",length
);
3639 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3642 LeaveCriticalSection( &freetype_cs
);
3646 static void dump_gdi_font_list(void)
3649 struct list
*elem_ptr
;
3651 TRACE("---------- gdiFont Cache ----------\n");
3652 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3653 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3654 TRACE("gdiFont=%p %s %d\n",
3655 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3658 TRACE("---------- Unused gdiFont Cache ----------\n");
3659 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3660 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3661 TRACE("gdiFont=%p %s %d\n",
3662 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3666 /*************************************************************
3667 * WineEngDestroyFontInstance
3669 * free the gdiFont associated with this handle
3672 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3677 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3680 EnterCriticalSection( &freetype_cs
);
3682 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3684 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3685 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3686 if(hflist
->hfont
== handle
)
3688 TRACE("removing child font %p from child list\n", gdiFont
);
3689 list_remove(&gdiFont
->entry
);
3690 LeaveCriticalSection( &freetype_cs
);
3695 TRACE("destroying hfont=%p\n", handle
);
3697 dump_gdi_font_list();
3699 font_elem_ptr
= list_head(&gdi_font_list
);
3700 while(font_elem_ptr
) {
3701 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3702 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3704 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3705 while(hfontlist_elem_ptr
) {
3706 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3707 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3708 if(hflist
->hfont
== handle
) {
3709 list_remove(&hflist
->entry
);
3710 HeapFree(GetProcessHeap(), 0, hflist
);
3714 if(list_empty(&gdiFont
->hfontlist
)) {
3715 TRACE("Moving to Unused list\n");
3716 list_remove(&gdiFont
->entry
);
3717 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3722 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3723 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3724 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3725 while(font_elem_ptr
) {
3726 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3727 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3728 TRACE("freeing %p\n", gdiFont
);
3729 list_remove(&gdiFont
->entry
);
3732 LeaveCriticalSection( &freetype_cs
);
3736 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3737 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3742 if (face
->cached_enum_data
)
3745 *pelf
= face
->cached_enum_data
->elf
;
3746 *pntm
= face
->cached_enum_data
->ntm
;
3747 *ptype
= face
->cached_enum_data
->type
;
3751 font
= alloc_font();
3753 if(face
->scalable
) {
3754 height
= -2048; /* 2048 is the most common em size */
3757 height
= face
->size
.y_ppem
>> 6;
3758 width
= face
->size
.x_ppem
>> 6;
3760 font
->scale_y
= 1.0;
3762 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3768 font
->name
= strdupW(face
->family
->FamilyName
);
3769 font
->ntmFlags
= face
->ntmFlags
;
3771 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3773 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3775 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3777 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3778 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3780 lstrcpynW(pelf
->elfFullName
,
3781 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
3783 lstrcpynW(pelf
->elfStyle
,
3784 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
3789 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
3791 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3793 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3794 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
3795 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
3798 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
3799 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3800 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3801 pntm
->ntmFontSig
= face
->fs
;
3803 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3805 pelf
->elfLogFont
.lfEscapement
= 0;
3806 pelf
->elfLogFont
.lfOrientation
= 0;
3807 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
3808 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3809 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
3810 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
3811 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
3812 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
3813 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
3814 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3815 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3816 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3817 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3820 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
3821 *ptype
|= TRUETYPE_FONTTYPE
;
3822 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
3823 *ptype
|= DEVICE_FONTTYPE
;
3824 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
3825 *ptype
|= RASTER_FONTTYPE
;
3827 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
3828 if (face
->cached_enum_data
)
3830 face
->cached_enum_data
->elf
= *pelf
;
3831 face
->cached_enum_data
->ntm
= *pntm
;
3832 face
->cached_enum_data
->type
= *ptype
;
3838 /*************************************************************
3842 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3846 struct list
*family_elem_ptr
, *face_elem_ptr
;
3848 NEWTEXTMETRICEXW ntm
;
3857 lf
.lfCharSet
= DEFAULT_CHARSET
;
3858 lf
.lfPitchAndFamily
= 0;
3859 lf
.lfFaceName
[0] = 0;
3863 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3865 EnterCriticalSection( &freetype_cs
);
3866 if(plf
->lfFaceName
[0]) {
3868 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3871 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3872 debugstr_w(psub
->to
.name
));
3874 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3878 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3879 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3880 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3881 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3882 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3883 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3884 for(i
= 0; i
< 32; i
++) {
3885 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3886 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3887 strcpyW(elf
.elfScript
, OEM_DOSW
);
3888 i
= 32; /* break out of loop */
3889 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3892 fs
.fsCsb
[0] = 1L << i
;
3894 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3896 csi
.ciCharset
= DEFAULT_CHARSET
;
3897 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3898 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3899 elf
.elfLogFont
.lfCharSet
=
3900 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3902 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3904 FIXME("Unknown elfscript for bit %d\n", i
);
3907 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3908 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3909 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3910 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3911 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3912 ntm
.ntmTm
.ntmFlags
);
3913 /* release section before callback (FIXME) */
3914 LeaveCriticalSection( &freetype_cs
);
3915 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3916 EnterCriticalSection( &freetype_cs
);
3922 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3923 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3924 face_elem_ptr
= list_head(&family
->faces
);
3925 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3926 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3927 for(i
= 0; i
< 32; i
++) {
3928 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3929 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3930 strcpyW(elf
.elfScript
, OEM_DOSW
);
3931 i
= 32; /* break out of loop */
3932 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3935 fs
.fsCsb
[0] = 1L << i
;
3937 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3939 csi
.ciCharset
= DEFAULT_CHARSET
;
3940 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3941 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3942 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3945 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3947 FIXME("Unknown elfscript for bit %d\n", i
);
3950 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3951 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3952 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3953 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3954 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3955 ntm
.ntmTm
.ntmFlags
);
3956 /* release section before callback (FIXME) */
3957 LeaveCriticalSection( &freetype_cs
);
3958 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3959 EnterCriticalSection( &freetype_cs
);
3963 LeaveCriticalSection( &freetype_cs
);
3967 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3969 pt
->x
.value
= vec
->x
>> 6;
3970 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3971 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3972 pt
->y
.value
= vec
->y
>> 6;
3973 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3974 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3978 /***************************************************
3979 * According to the MSDN documentation on WideCharToMultiByte,
3980 * certain codepages cannot set the default_used parameter.
3981 * This returns TRUE if the codepage can set that parameter, false else
3982 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3984 static BOOL
codepage_sets_default_used(UINT codepage
)
3998 * GSUB Table handling functions
4001 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4003 const GSUB_CoverageFormat1
* cf1
;
4005 cf1
= (GSUB_CoverageFormat1
*)table
;
4007 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4009 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4011 TRACE("Coverage Format 1, %i glyphs\n",count
);
4012 for (i
= 0; i
< count
; i
++)
4013 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4017 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4019 const GSUB_CoverageFormat2
* cf2
;
4022 cf2
= (GSUB_CoverageFormat2
*)cf1
;
4024 count
= GET_BE_WORD(cf2
->RangeCount
);
4025 TRACE("Coverage Format 2, %i ranges\n",count
);
4026 for (i
= 0; i
< count
; i
++)
4028 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4030 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4031 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4033 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4034 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4040 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4045 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4047 const GSUB_ScriptList
*script
;
4048 const GSUB_Script
*deflt
= NULL
;
4050 script
= (GSUB_ScriptList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->ScriptList
));
4052 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4053 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4055 const GSUB_Script
*scr
;
4058 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4059 scr
= (GSUB_Script
*)((LPBYTE
)script
+ offset
);
4061 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4063 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4069 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4073 const GSUB_LangSys
*Lang
;
4075 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4077 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4079 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4080 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
4082 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4085 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4088 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
4094 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4097 const GSUB_FeatureList
*feature
;
4098 feature
= (GSUB_FeatureList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->FeatureList
));
4100 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4101 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4103 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4104 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4106 const GSUB_Feature
*feat
;
4107 feat
= (GSUB_Feature
*)((LPBYTE
)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4114 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4118 const GSUB_LookupList
*lookup
;
4119 lookup
= (GSUB_LookupList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->LookupList
));
4121 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4122 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4124 const GSUB_LookupTable
*look
;
4125 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4126 look
= (GSUB_LookupTable
*)((LPBYTE
)lookup
+ offset
);
4127 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4128 if (GET_BE_WORD(look
->LookupType
) != 1)
4129 FIXME("We only handle SubType 1\n");
4134 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4136 const GSUB_SingleSubstFormat1
*ssf1
;
4137 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4138 ssf1
= (GSUB_SingleSubstFormat1
*)((LPBYTE
)look
+offset
);
4139 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4141 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4142 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4143 if (GSUB_is_glyph_covered((LPBYTE
)ssf1
+offset
, glyph
) != -1)
4145 TRACE(" Glyph 0x%x ->",glyph
);
4146 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4147 TRACE(" 0x%x\n",glyph
);
4152 const GSUB_SingleSubstFormat2
*ssf2
;
4156 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
4157 offset
= GET_BE_WORD(ssf1
->Coverage
);
4158 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4159 index
= GSUB_is_glyph_covered((LPBYTE
)ssf2
+offset
, glyph
);
4160 TRACE(" Coverage index %i\n",index
);
4163 TRACE(" Glyph is 0x%x ->",glyph
);
4164 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4165 TRACE("0x%x\n",glyph
);
4174 static const char* get_opentype_script(const GdiFont
*font
)
4177 * I am not sure if this is the correct way to generate our script tag
4180 switch (font
->charset
)
4182 case ANSI_CHARSET
: return "latn";
4183 case BALTIC_CHARSET
: return "latn"; /* ?? */
4184 case CHINESEBIG5_CHARSET
: return "hani";
4185 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4186 case GB2312_CHARSET
: return "hani";
4187 case GREEK_CHARSET
: return "grek";
4188 case HANGUL_CHARSET
: return "hang";
4189 case RUSSIAN_CHARSET
: return "cyrl";
4190 case SHIFTJIS_CHARSET
: return "kana";
4191 case TURKISH_CHARSET
: return "latn"; /* ?? */
4192 case VIETNAMESE_CHARSET
: return "latn";
4193 case JOHAB_CHARSET
: return "latn"; /* ?? */
4194 case ARABIC_CHARSET
: return "arab";
4195 case HEBREW_CHARSET
: return "hebr";
4196 case THAI_CHARSET
: return "thai";
4197 default: return "latn";
4201 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4203 const GSUB_Header
*header
;
4204 const GSUB_Script
*script
;
4205 const GSUB_LangSys
*language
;
4206 const GSUB_Feature
*feature
;
4208 if (!font
->GSUB_Table
)
4211 header
= font
->GSUB_Table
;
4213 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4216 TRACE("Script not found\n");
4219 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4222 TRACE("Language not found\n");
4225 feature
= GSUB_get_feature(header
, language
, "vrt2");
4227 feature
= GSUB_get_feature(header
, language
, "vert");
4230 TRACE("vrt2/vert feature not found\n");
4233 return GSUB_apply_feature(header
, feature
, glyph
);
4236 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4240 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4241 WCHAR wc
= (WCHAR
)glyph
;
4243 BOOL
*default_used_pointer
;
4246 default_used_pointer
= NULL
;
4247 default_used
= FALSE
;
4248 if (codepage_sets_default_used(font
->codepage
))
4249 default_used_pointer
= &default_used
;
4250 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4253 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4254 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4255 return get_GSUB_vert_glyph(font
,ret
);
4258 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
&& glyph
< 0x100)
4259 glyph
= glyph
+ 0xf000;
4260 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4261 return get_GSUB_vert_glyph(font
,glyphId
);
4264 /*************************************************************
4265 * WineEngGetGlyphIndices
4268 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4269 LPWORD pgi
, DWORD flags
)
4272 int default_char
= -1;
4274 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4276 for(i
= 0; i
< count
; i
++)
4278 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4281 if (default_char
== -1)
4283 if (FT_IS_SFNT(font
->ft_face
))
4285 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4286 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4291 WineEngGetTextMetrics(font
, &textm
);
4292 default_char
= textm
.tmDefaultChar
;
4295 pgi
[i
] = default_char
;
4301 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
4303 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
4304 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
4307 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
4309 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
4310 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
4313 /*************************************************************
4314 * WineEngGetGlyphOutline
4316 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4317 * except that the first parameter is the HWINEENGFONT of the font in
4318 * question rather than an HDC.
4321 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4322 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4325 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4326 FT_Face ft_face
= incoming_font
->ft_face
;
4327 GdiFont
*font
= incoming_font
;
4328 FT_UInt glyph_index
;
4329 DWORD width
, height
, pitch
, needed
= 0;
4330 FT_Bitmap ft_bitmap
;
4332 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4334 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4335 double widthRatio
= 1.0;
4336 FT_Matrix transMat
= identityMat
;
4337 FT_Matrix transMatUnrotated
;
4338 BOOL needsTransform
= FALSE
;
4339 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4340 UINT original_index
;
4342 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4343 buflen
, buf
, lpmat
);
4345 TRACE("font transform %f %f %f %f\n",
4346 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
4347 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
4349 EnterCriticalSection( &freetype_cs
);
4351 if(format
& GGO_GLYPH_INDEX
) {
4352 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4353 original_index
= glyph
;
4354 format
&= ~GGO_GLYPH_INDEX
;
4356 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4357 ft_face
= font
->ft_face
;
4358 original_index
= glyph_index
;
4361 /* tategaki never appears to happen to lower glyph index */
4362 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4365 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4366 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4367 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4368 font
->gmsize
* sizeof(GM
*));
4370 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
4371 FONT_GM(font
,original_index
)->init
&& (!lpmat
|| is_identity_MAT2(lpmat
)))
4373 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4374 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4375 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4376 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4377 LeaveCriticalSection( &freetype_cs
);
4378 return 1; /* FIXME */
4382 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4383 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4385 /* Scaling factor */
4390 WineEngGetTextMetrics(font
, &tm
);
4392 widthRatio
= (double)font
->aveWidth
;
4393 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4396 widthRatio
= font
->scale_y
;
4398 /* Scaling transform */
4399 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
4402 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4405 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4407 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4408 needsTransform
= TRUE
;
4411 /* Slant transform */
4412 if (font
->fake_italic
) {
4415 slantMat
.xx
= (1 << 16);
4416 slantMat
.xy
= ((1 << 16) >> 2);
4418 slantMat
.yy
= (1 << 16);
4419 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4420 needsTransform
= TRUE
;
4423 /* Rotation transform */
4424 transMatUnrotated
= transMat
;
4425 if(font
->orientation
&& !tategaki
) {
4426 FT_Matrix rotationMat
;
4428 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
4429 pFT_Vector_Unit(&vecAngle
, angle
);
4430 rotationMat
.xx
= vecAngle
.x
;
4431 rotationMat
.xy
= -vecAngle
.y
;
4432 rotationMat
.yx
= -rotationMat
.xy
;
4433 rotationMat
.yy
= rotationMat
.xx
;
4435 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4436 needsTransform
= TRUE
;
4439 /* World transform */
4440 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
4443 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
4444 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
4445 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
4446 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
4447 pFT_Matrix_Multiply(&worldMat
, &transMat
);
4448 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
4449 needsTransform
= TRUE
;
4452 /* Extra transformation specified by caller */
4453 if (lpmat
&& !is_identity_MAT2(lpmat
))
4456 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4457 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
4458 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
4459 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4460 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4461 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
4462 needsTransform
= TRUE
;
4465 if (needsTransform
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
))
4466 load_flags
|= FT_LOAD_NO_BITMAP
;
4468 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4471 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4472 LeaveCriticalSection( &freetype_cs
);
4476 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
4477 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
4479 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
) + 63) >> 6;
4481 bbx
= (right
- left
) >> 6;
4483 if(!needsTransform
) {
4484 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4485 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4486 ft_face
->glyph
->metrics
.height
) & -64;
4487 lpgm
->gmCellIncX
= adv
;
4488 lpgm
->gmCellIncY
= 0;
4492 for(xc
= 0; xc
< 2; xc
++) {
4493 for(yc
= 0; yc
< 2; yc
++) {
4494 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4495 xc
* ft_face
->glyph
->metrics
.width
);
4496 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4497 yc
* ft_face
->glyph
->metrics
.height
;
4498 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4499 pFT_Vector_Transform(&vec
, &transMat
);
4500 if(xc
== 0 && yc
== 0) {
4501 left
= right
= vec
.x
;
4502 top
= bottom
= vec
.y
;
4504 if(vec
.x
< left
) left
= vec
.x
;
4505 else if(vec
.x
> right
) right
= vec
.x
;
4506 if(vec
.y
< bottom
) bottom
= vec
.y
;
4507 else if(vec
.y
> top
) top
= vec
.y
;
4512 right
= (right
+ 63) & -64;
4513 bottom
= bottom
& -64;
4514 top
= (top
+ 63) & -64;
4516 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4517 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4519 pFT_Vector_Transform(&vec
, &transMat
);
4520 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4521 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4523 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4525 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
4526 adv
= (vec
.x
+63) >> 6;
4528 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4529 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4530 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4531 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4533 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4534 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4535 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4537 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
4538 (!lpmat
|| is_identity_MAT2(lpmat
))) /* don't cache custom transforms */
4540 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4541 FONT_GM(font
,original_index
)->adv
= adv
;
4542 FONT_GM(font
,original_index
)->lsb
= lsb
;
4543 FONT_GM(font
,original_index
)->bbx
= bbx
;
4544 FONT_GM(font
,original_index
)->init
= TRUE
;
4547 if(format
== GGO_METRICS
)
4549 LeaveCriticalSection( &freetype_cs
);
4550 return 1; /* FIXME */
4553 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) {
4554 TRACE("loaded a bitmap\n");
4555 LeaveCriticalSection( &freetype_cs
);
4561 width
= lpgm
->gmBlackBoxX
;
4562 height
= lpgm
->gmBlackBoxY
;
4563 pitch
= ((width
+ 31) >> 5) << 2;
4564 needed
= pitch
* height
;
4566 if(!buf
|| !buflen
) break;
4568 switch(ft_face
->glyph
->format
) {
4569 case ft_glyph_format_bitmap
:
4571 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4572 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4573 INT h
= ft_face
->glyph
->bitmap
.rows
;
4575 memcpy(dst
, src
, w
);
4576 src
+= ft_face
->glyph
->bitmap
.pitch
;
4582 case ft_glyph_format_outline
:
4583 ft_bitmap
.width
= width
;
4584 ft_bitmap
.rows
= height
;
4585 ft_bitmap
.pitch
= pitch
;
4586 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4587 ft_bitmap
.buffer
= buf
;
4589 if(needsTransform
) {
4590 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4593 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4595 /* Note: FreeType will only set 'black' bits for us. */
4596 memset(buf
, 0, needed
);
4597 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4601 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4602 LeaveCriticalSection( &freetype_cs
);
4607 case GGO_GRAY2_BITMAP
:
4608 case GGO_GRAY4_BITMAP
:
4609 case GGO_GRAY8_BITMAP
:
4610 case WINE_GGO_GRAY16_BITMAP
:
4612 unsigned int mult
, row
, col
;
4615 width
= lpgm
->gmBlackBoxX
;
4616 height
= lpgm
->gmBlackBoxY
;
4617 pitch
= (width
+ 3) / 4 * 4;
4618 needed
= pitch
* height
;
4620 if(!buf
|| !buflen
) break;
4622 switch(ft_face
->glyph
->format
) {
4623 case ft_glyph_format_bitmap
:
4625 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4626 INT h
= ft_face
->glyph
->bitmap
.rows
;
4629 for(x
= 0; x
< pitch
; x
++)
4631 if(x
< ft_face
->glyph
->bitmap
.width
)
4632 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
4636 src
+= ft_face
->glyph
->bitmap
.pitch
;
4639 LeaveCriticalSection( &freetype_cs
);
4642 case ft_glyph_format_outline
:
4644 ft_bitmap
.width
= width
;
4645 ft_bitmap
.rows
= height
;
4646 ft_bitmap
.pitch
= pitch
;
4647 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4648 ft_bitmap
.buffer
= buf
;
4651 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4653 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4655 memset(ft_bitmap
.buffer
, 0, buflen
);
4657 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4659 if(format
== GGO_GRAY2_BITMAP
)
4661 else if(format
== GGO_GRAY4_BITMAP
)
4663 else if(format
== GGO_GRAY8_BITMAP
)
4665 else /* format == WINE_GGO_GRAY16_BITMAP */
4667 LeaveCriticalSection( &freetype_cs
);
4673 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4674 LeaveCriticalSection( &freetype_cs
);
4679 for(row
= 0; row
< height
; row
++) {
4681 for(col
= 0; col
< width
; col
++, ptr
++) {
4682 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4691 int contour
, point
= 0, first_pt
;
4692 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4693 TTPOLYGONHEADER
*pph
;
4695 DWORD pph_start
, cpfx
, type
;
4697 if(buflen
== 0) buf
= NULL
;
4699 if (needsTransform
&& buf
) {
4700 pFT_Outline_Transform(outline
, &transMat
);
4703 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4705 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4708 pph
->dwType
= TT_POLYGON_TYPE
;
4709 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4711 needed
+= sizeof(*pph
);
4713 while(point
<= outline
->contours
[contour
]) {
4714 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4715 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4716 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
4720 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4723 } while(point
<= outline
->contours
[contour
] &&
4724 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4725 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4726 /* At the end of a contour Windows adds the start point, but
4728 if(point
> outline
->contours
[contour
] &&
4729 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4731 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
4733 } else if(point
<= outline
->contours
[contour
] &&
4734 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4735 /* add closing pt for bezier */
4737 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4745 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4748 pph
->cb
= needed
- pph_start
;
4754 /* Convert the quadratic Beziers to cubic Beziers.
4755 The parametric eqn for a cubic Bezier is, from PLRM:
4756 r(t) = at^3 + bt^2 + ct + r0
4757 with the control points:
4762 A quadratic Beizer has the form:
4763 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4765 So equating powers of t leads to:
4766 r1 = 2/3 p1 + 1/3 p0
4767 r2 = 2/3 p1 + 1/3 p2
4768 and of course r0 = p0, r3 = p2
4771 int contour
, point
= 0, first_pt
;
4772 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4773 TTPOLYGONHEADER
*pph
;
4775 DWORD pph_start
, cpfx
, type
;
4776 FT_Vector cubic_control
[4];
4777 if(buflen
== 0) buf
= NULL
;
4779 if (needsTransform
&& buf
) {
4780 pFT_Outline_Transform(outline
, &transMat
);
4783 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4785 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4788 pph
->dwType
= TT_POLYGON_TYPE
;
4789 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4791 needed
+= sizeof(*pph
);
4793 while(point
<= outline
->contours
[contour
]) {
4794 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4795 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4796 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
4799 if(type
== TT_PRIM_LINE
) {
4801 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4805 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4808 /* FIXME: Possible optimization in endpoint calculation
4809 if there are two consecutive curves */
4810 cubic_control
[0] = outline
->points
[point
-1];
4811 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4812 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
4813 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
4814 cubic_control
[0].x
>>= 1;
4815 cubic_control
[0].y
>>= 1;
4817 if(point
+1 > outline
->contours
[contour
])
4818 cubic_control
[3] = outline
->points
[first_pt
];
4820 cubic_control
[3] = outline
->points
[point
+1];
4821 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
4822 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
4823 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
4824 cubic_control
[3].x
>>= 1;
4825 cubic_control
[3].y
>>= 1;
4828 /* r1 = 1/3 p0 + 2/3 p1
4829 r2 = 1/3 p2 + 2/3 p1 */
4830 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
4831 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
4832 cubic_control
[2] = cubic_control
[1];
4833 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
4834 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
4835 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
4836 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
4838 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
4839 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
4840 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
4845 } while(point
<= outline
->contours
[contour
] &&
4846 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4847 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4848 /* At the end of a contour Windows adds the start point,
4849 but only for Beziers and we've already done that.
4851 if(point
<= outline
->contours
[contour
] &&
4852 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4853 /* This is the closing pt of a bezier, but we've already
4854 added it, so just inc point and carry on */
4861 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4864 pph
->cb
= needed
- pph_start
;
4870 FIXME("Unsupported format %d\n", format
);
4871 LeaveCriticalSection( &freetype_cs
);
4874 LeaveCriticalSection( &freetype_cs
);
4878 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
4880 FT_Face ft_face
= font
->ft_face
;
4881 #ifdef HAVE_FREETYPE_FTWINFNT_H
4882 FT_WinFNT_HeaderRec winfnt_header
;
4884 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
4885 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
4886 font
->potm
->otmSize
= size
;
4888 #define TM font->potm->otmTextMetrics
4889 #ifdef HAVE_FREETYPE_FTWINFNT_H
4890 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
4892 TM
.tmHeight
= winfnt_header
.pixel_height
;
4893 TM
.tmAscent
= winfnt_header
.ascent
;
4894 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
4895 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
4896 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
4897 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
4898 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4899 TM
.tmWeight
= winfnt_header
.weight
;
4901 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4902 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4903 TM
.tmFirstChar
= winfnt_header
.first_char
;
4904 TM
.tmLastChar
= winfnt_header
.last_char
;
4905 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4906 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4907 TM
.tmItalic
= winfnt_header
.italic
;
4908 TM
.tmUnderlined
= font
->underline
;
4909 TM
.tmStruckOut
= font
->strikeout
;
4910 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4911 TM
.tmCharSet
= winfnt_header
.charset
;
4916 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4917 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4918 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4919 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4920 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4921 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4922 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4923 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4925 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4926 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4928 TM
.tmLastChar
= 255;
4929 TM
.tmDefaultChar
= 32;
4930 TM
.tmBreakChar
= 32;
4931 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4932 TM
.tmUnderlined
= font
->underline
;
4933 TM
.tmStruckOut
= font
->strikeout
;
4934 /* NB inverted meaning of TMPF_FIXED_PITCH */
4935 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4936 TM
.tmCharSet
= font
->charset
;
4944 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
4946 double scale_x
, scale_y
;
4950 scale_x
= (double)font
->aveWidth
;
4951 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4954 scale_x
= font
->scale_y
;
4956 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
4957 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
4959 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4960 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4962 SCALE_Y(ptm
->tmHeight
);
4963 SCALE_Y(ptm
->tmAscent
);
4964 SCALE_Y(ptm
->tmDescent
);
4965 SCALE_Y(ptm
->tmInternalLeading
);
4966 SCALE_Y(ptm
->tmExternalLeading
);
4967 SCALE_Y(ptm
->tmOverhang
);
4969 SCALE_X(ptm
->tmAveCharWidth
);
4970 SCALE_X(ptm
->tmMaxCharWidth
);
4976 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
4978 double scale_x
, scale_y
;
4982 scale_x
= (double)font
->aveWidth
;
4983 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4986 scale_x
= font
->scale_y
;
4988 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
4989 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
4991 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4993 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4994 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4996 SCALE_Y(potm
->otmAscent
);
4997 SCALE_Y(potm
->otmDescent
);
4998 SCALE_Y(potm
->otmLineGap
);
4999 SCALE_Y(potm
->otmsCapEmHeight
);
5000 SCALE_Y(potm
->otmsXHeight
);
5001 SCALE_Y(potm
->otmrcFontBox
.top
);
5002 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5003 SCALE_X(potm
->otmrcFontBox
.left
);
5004 SCALE_X(potm
->otmrcFontBox
.right
);
5005 SCALE_Y(potm
->otmMacAscent
);
5006 SCALE_Y(potm
->otmMacDescent
);
5007 SCALE_Y(potm
->otmMacLineGap
);
5008 SCALE_X(potm
->otmptSubscriptSize
.x
);
5009 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5010 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5011 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5012 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5013 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5014 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5015 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5016 SCALE_Y(potm
->otmsStrikeoutSize
);
5017 SCALE_Y(potm
->otmsStrikeoutPosition
);
5018 SCALE_Y(potm
->otmsUnderscoreSize
);
5019 SCALE_Y(potm
->otmsUnderscorePosition
);
5025 /*************************************************************
5026 * WineEngGetTextMetrics
5029 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5031 EnterCriticalSection( &freetype_cs
);
5033 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
5034 if(!get_bitmap_text_metrics(font
))
5036 LeaveCriticalSection( &freetype_cs
);
5042 LeaveCriticalSection( &freetype_cs
);
5045 *ptm
= font
->potm
->otmTextMetrics
;
5046 scale_font_metrics(font
, ptm
);
5047 LeaveCriticalSection( &freetype_cs
);
5052 /*************************************************************
5053 * WineEngGetOutlineTextMetrics
5056 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5057 OUTLINETEXTMETRICW
*potm
)
5059 FT_Face ft_face
= font
->ft_face
;
5060 UINT needed
, lenfam
, lensty
, ret
;
5062 TT_HoriHeader
*pHori
;
5063 TT_Postscript
*pPost
;
5064 FT_Fixed x_scale
, y_scale
;
5065 WCHAR
*family_nameW
, *style_nameW
;
5066 static const WCHAR spaceW
[] = {' ', '\0'};
5068 INT ascent
, descent
;
5070 TRACE("font=%p\n", font
);
5072 if(!FT_IS_SCALABLE(ft_face
))
5075 EnterCriticalSection( &freetype_cs
);
5078 if(cbSize
>= font
->potm
->otmSize
)
5080 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5081 scale_outline_font_metrics(font
, potm
);
5083 LeaveCriticalSection( &freetype_cs
);
5084 return font
->potm
->otmSize
;
5088 needed
= sizeof(*potm
);
5090 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
5091 family_nameW
= strdupW(font
->name
);
5093 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
5095 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
5096 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
5097 style_nameW
, lensty
/sizeof(WCHAR
));
5099 /* These names should be read from the TT name table */
5101 /* length of otmpFamilyName */
5104 /* length of otmpFaceName */
5105 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
5106 needed
+= lenfam
; /* just the family name */
5108 needed
+= lenfam
+ lensty
; /* family + " " + style */
5111 /* length of otmpStyleName */
5114 /* length of otmpFullName */
5115 needed
+= lenfam
+ lensty
;
5118 x_scale
= ft_face
->size
->metrics
.x_scale
;
5119 y_scale
= ft_face
->size
->metrics
.y_scale
;
5121 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
5123 FIXME("Can't find OS/2 table - not TT font?\n");
5128 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
5130 FIXME("Can't find HHEA table - not TT font?\n");
5135 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
5137 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",
5138 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
5139 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
5140 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
5141 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
5142 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
5144 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
5145 font
->potm
->otmSize
= needed
;
5147 #define TM font->potm->otmTextMetrics
5149 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
5150 ascent
= pHori
->Ascender
;
5151 descent
= -pHori
->Descender
;
5153 ascent
= pOS2
->usWinAscent
;
5154 descent
= pOS2
->usWinDescent
;
5158 TM
.tmAscent
= font
->yMax
;
5159 TM
.tmDescent
= -font
->yMin
;
5160 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
5162 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
5163 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
5164 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
5165 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
5168 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5171 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5173 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
5174 ((ascent
+ descent
) -
5175 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
5177 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
5178 if (TM
.tmAveCharWidth
== 0) {
5179 TM
.tmAveCharWidth
= 1;
5181 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5182 TM
.tmWeight
= (font
->fake_bold
|| (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)) ? FW_BOLD
: FW_REGULAR
;
5184 TM
.tmDigitizedAspectX
= 300;
5185 TM
.tmDigitizedAspectY
= 300;
5186 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5187 * symbol range to 0 - f0ff
5189 if (font
->charset
== SYMBOL_CHARSET
)
5192 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
5196 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
5197 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0xffff;
5199 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
5200 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
5201 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
5202 TM
.tmUnderlined
= font
->underline
;
5203 TM
.tmStruckOut
= font
->strikeout
;
5205 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5206 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
5207 (pOS2
->version
== 0xFFFFU
||
5208 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
5209 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
5211 TM
.tmPitchAndFamily
= 0;
5213 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
5214 case PAN_FAMILY_SCRIPT
:
5215 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
5217 case PAN_FAMILY_DECORATIVE
:
5218 case PAN_FAMILY_PICTORIAL
:
5219 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
5221 case PAN_FAMILY_TEXT_DISPLAY
:
5222 if(TM
.tmPitchAndFamily
== 0) /* fixed */
5223 TM
.tmPitchAndFamily
= FF_MODERN
;
5225 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
5226 case PAN_SERIF_NORMAL_SANS
:
5227 case PAN_SERIF_OBTUSE_SANS
:
5228 case PAN_SERIF_PERP_SANS
:
5229 TM
.tmPitchAndFamily
|= FF_SWISS
;
5232 TM
.tmPitchAndFamily
|= FF_ROMAN
;
5237 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
5240 if(FT_IS_SCALABLE(ft_face
))
5241 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
5243 if(FT_IS_SFNT(ft_face
))
5245 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
5246 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
5248 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
5251 TM
.tmCharSet
= font
->charset
;
5253 font
->potm
->otmFiller
= 0;
5254 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
5255 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
5256 font
->potm
->otmfsType
= pOS2
->fsType
;
5257 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
5258 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
5259 font
->potm
->otmItalicAngle
= 0; /* POST table */
5260 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
5261 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
5262 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
5263 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
5264 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
5265 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5266 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5267 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5268 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5269 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5270 font
->potm
->otmMacAscent
= TM
.tmAscent
;
5271 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
5272 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
5273 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5274 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5275 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5276 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5277 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5278 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5279 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5280 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5281 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5282 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5283 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5285 font
->potm
->otmsUnderscoreSize
= 0;
5286 font
->potm
->otmsUnderscorePosition
= 0;
5288 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5289 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5293 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5294 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5295 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5296 strcpyW((WCHAR
*)cp
, family_nameW
);
5298 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5299 strcpyW((WCHAR
*)cp
, style_nameW
);
5301 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5302 strcpyW((WCHAR
*)cp
, family_nameW
);
5303 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
5304 strcatW((WCHAR
*)cp
, spaceW
);
5305 strcatW((WCHAR
*)cp
, style_nameW
);
5306 cp
+= lenfam
+ lensty
;
5309 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5310 strcpyW((WCHAR
*)cp
, family_nameW
);
5311 strcatW((WCHAR
*)cp
, spaceW
);
5312 strcatW((WCHAR
*)cp
, style_nameW
);
5315 if(potm
&& needed
<= cbSize
)
5317 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5318 scale_outline_font_metrics(font
, potm
);
5322 HeapFree(GetProcessHeap(), 0, style_nameW
);
5323 HeapFree(GetProcessHeap(), 0, family_nameW
);
5325 LeaveCriticalSection( &freetype_cs
);
5329 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5331 HFONTLIST
*hfontlist
;
5332 child
->font
= alloc_font();
5333 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5334 if(!child
->font
->ft_face
)
5336 free_font(child
->font
);
5341 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5342 child
->font
->orientation
= font
->orientation
;
5343 child
->font
->scale_y
= font
->scale_y
;
5344 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5345 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5346 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5347 child
->font
->base_font
= font
;
5348 list_add_head(&child_font_list
, &child
->font
->entry
);
5349 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5353 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5356 CHILD_FONT
*child_font
;
5359 font
= font
->base_font
;
5361 *linked_font
= font
;
5363 if((*glyph
= get_glyph_index(font
, c
)))
5366 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5368 if(!child_font
->font
)
5369 if(!load_child_font(font
, child_font
))
5372 if(!child_font
->font
->ft_face
)
5374 g
= get_glyph_index(child_font
->font
, c
);
5378 *linked_font
= child_font
->font
;
5385 /*************************************************************
5386 * WineEngGetCharWidth
5389 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5394 FT_UInt glyph_index
;
5395 GdiFont
*linked_font
;
5397 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5399 EnterCriticalSection( &freetype_cs
);
5400 for(c
= firstChar
; c
<= lastChar
; c
++) {
5401 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5402 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5403 &gm
, 0, NULL
, NULL
);
5404 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5406 LeaveCriticalSection( &freetype_cs
);
5410 /*************************************************************
5411 * WineEngGetCharABCWidths
5414 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5419 FT_UInt glyph_index
;
5420 GdiFont
*linked_font
;
5422 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5424 if(!FT_IS_SCALABLE(font
->ft_face
))
5427 EnterCriticalSection( &freetype_cs
);
5429 for(c
= firstChar
; c
<= lastChar
; c
++) {
5430 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5431 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5432 &gm
, 0, NULL
, NULL
);
5433 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
5434 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
5435 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
5436 FONT_GM(linked_font
,glyph_index
)->bbx
;
5438 LeaveCriticalSection( &freetype_cs
);
5442 /*************************************************************
5443 * WineEngGetCharABCWidthsI
5446 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5451 FT_UInt glyph_index
;
5452 GdiFont
*linked_font
;
5454 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
5457 EnterCriticalSection( &freetype_cs
);
5459 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
5461 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
5462 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5463 &gm
, 0, NULL
, NULL
);
5464 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
5465 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
5466 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
5467 - FONT_GM(linked_font
,c
)->bbx
;
5470 for(c
= 0; c
< count
; c
++) {
5471 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
5472 &gm
, 0, NULL
, NULL
);
5473 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
5474 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
5475 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
5476 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
5479 LeaveCriticalSection( &freetype_cs
);
5483 /*************************************************************
5484 * WineEngGetTextExtentExPoint
5487 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5488 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5494 FT_UInt glyph_index
;
5495 GdiFont
*linked_font
;
5497 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
5500 EnterCriticalSection( &freetype_cs
);
5503 WineEngGetTextMetrics(font
, &tm
);
5504 size
->cy
= tm
.tmHeight
;
5506 for(idx
= 0; idx
< count
; idx
++) {
5507 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
5508 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5509 &gm
, 0, NULL
, NULL
);
5510 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
5512 if (! pnfit
|| ext
<= max_ext
) {
5522 LeaveCriticalSection( &freetype_cs
);
5523 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5527 /*************************************************************
5528 * WineEngGetTextExtentExPointI
5531 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5532 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5539 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
5541 EnterCriticalSection( &freetype_cs
);
5544 WineEngGetTextMetrics(font
, &tm
);
5545 size
->cy
= tm
.tmHeight
;
5547 for(idx
= 0; idx
< count
; idx
++) {
5548 WineEngGetGlyphOutline(font
, indices
[idx
],
5549 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
5551 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
5553 if (! pnfit
|| ext
<= max_ext
) {
5563 LeaveCriticalSection( &freetype_cs
);
5564 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5568 /*************************************************************
5569 * WineEngGetFontData
5572 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5575 FT_Face ft_face
= font
->ft_face
;
5579 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5580 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
5581 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
5583 if(!FT_IS_SFNT(ft_face
))
5591 if(table
) { /* MS tags differ in endianness from FT ones */
5592 table
= table
>> 24 | table
<< 24 |
5593 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
5596 /* make sure value of len is the value freetype says it needs */
5599 FT_ULong needed
= 0;
5600 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
5601 if( !err
&& needed
< len
) len
= needed
;
5603 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
5606 TRACE("Can't find table %c%c%c%c\n",
5607 /* bytes were reversed */
5608 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
5609 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
5615 /*************************************************************
5616 * WineEngGetTextFace
5619 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5621 INT n
= strlenW(font
->name
) + 1;
5623 lstrcpynW(str
, font
->name
, count
);
5624 return min(count
, n
);
5629 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5631 if (fs
) *fs
= font
->fs
;
5632 return font
->charset
;
5635 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5637 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
5638 struct list
*first_hfont
;
5641 EnterCriticalSection( &freetype_cs
);
5642 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
5643 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
5644 if(font
== linked_font
)
5645 *new_hfont
= dc
->hFont
;
5648 first_hfont
= list_head(&linked_font
->hfontlist
);
5649 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
5651 LeaveCriticalSection( &freetype_cs
);
5655 /* Retrieve a list of supported Unicode ranges for a given font.
5656 * Can be called with NULL gs to calculate the buffer size. Returns
5657 * the number of ranges found.
5659 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
5661 DWORD num_ranges
= 0;
5663 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5666 FT_ULong char_code
, char_code_prev
;
5669 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
5671 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5672 face
->num_glyphs
, glyph_code
, char_code
);
5674 if (!glyph_code
) return 0;
5678 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
5679 gs
->ranges
[0].cGlyphs
= 0;
5680 gs
->cGlyphsSupported
= 0;
5686 if (char_code
< char_code_prev
)
5688 ERR("expected increasing char code from FT_Get_Next_Char\n");
5691 if (char_code
- char_code_prev
> 1)
5696 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
5697 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
5698 gs
->cGlyphsSupported
++;
5703 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
5704 gs
->cGlyphsSupported
++;
5706 char_code_prev
= char_code
;
5707 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
5711 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
5716 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5719 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
5721 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
5724 glyphset
->cbThis
= size
;
5725 glyphset
->cRanges
= num_ranges
;
5730 /*************************************************************
5733 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5736 EnterCriticalSection( &freetype_cs
);
5737 ret
= !list_empty(&font
->child_fonts
);
5738 LeaveCriticalSection( &freetype_cs
);
5742 static BOOL
is_hinting_enabled(void)
5744 /* Use the >= 2.2.0 function if available */
5745 if(pFT_Get_TrueType_Engine_Type
)
5747 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
5748 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
5750 #ifdef FT_DRIVER_HAS_HINTER
5755 /* otherwise if we've been compiled with < 2.2.0 headers
5756 use the internal macro */
5757 mod
= pFT_Get_Module(library
, "truetype");
5758 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
5766 /*************************************************************************
5767 * GetRasterizerCaps (GDI32.@)
5769 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5771 static int hinting
= -1;
5775 hinting
= is_hinting_enabled();
5776 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
5779 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5780 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
5781 lprs
->nLanguageID
= 0;
5785 /*************************************************************
5786 * WineEngRealizationInfo
5788 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
5790 FIXME("(%p, %p): stub!\n", font
, info
);
5793 if(FT_IS_SCALABLE(font
->ft_face
))
5796 info
->cache_num
= font
->cache_num
;
5797 info
->unknown2
= -1;
5801 /*************************************************************************
5802 * Kerning support for TrueType fonts
5804 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5806 struct TT_kern_table
5812 struct TT_kern_subtable
5821 USHORT horizontal
: 1;
5823 USHORT cross_stream
: 1;
5824 USHORT override
: 1;
5825 USHORT reserved1
: 4;
5831 struct TT_format0_kern_subtable
5835 USHORT entrySelector
;
5846 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
5847 const struct TT_format0_kern_subtable
*tt_f0_ks
,
5848 const USHORT
*glyph_to_char
,
5849 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
5852 const struct TT_kern_pair
*tt_kern_pair
;
5854 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
5856 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
5858 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5859 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
5860 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
5862 if (!kern_pair
|| !cPairs
)
5865 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
5867 nPairs
= min(nPairs
, cPairs
);
5869 for (i
= 0; i
< nPairs
; i
++)
5871 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
5872 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
5873 /* this algorithm appears to better match what Windows does */
5874 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
5875 if (kern_pair
->iKernAmount
< 0)
5877 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
5878 kern_pair
->iKernAmount
-= font
->ppem
;
5880 else if (kern_pair
->iKernAmount
> 0)
5882 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
5883 kern_pair
->iKernAmount
+= font
->ppem
;
5885 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
5887 TRACE("left %u right %u value %d\n",
5888 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
5892 TRACE("copied %u entries\n", nPairs
);
5896 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5900 const struct TT_kern_table
*tt_kern_table
;
5901 const struct TT_kern_subtable
*tt_kern_subtable
;
5903 USHORT
*glyph_to_char
;
5905 EnterCriticalSection( &freetype_cs
);
5906 if (font
->total_kern_pairs
!= (DWORD
)-1)
5908 if (cPairs
&& kern_pair
)
5910 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5911 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5912 LeaveCriticalSection( &freetype_cs
);
5915 LeaveCriticalSection( &freetype_cs
);
5916 return font
->total_kern_pairs
;
5919 font
->total_kern_pairs
= 0;
5921 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
5923 if (length
== GDI_ERROR
)
5925 TRACE("no kerning data in the font\n");
5926 LeaveCriticalSection( &freetype_cs
);
5930 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
5933 WARN("Out of memory\n");
5934 LeaveCriticalSection( &freetype_cs
);
5938 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
5940 /* build a glyph index to char code map */
5941 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
5944 WARN("Out of memory allocating a glyph index to char code map\n");
5945 HeapFree(GetProcessHeap(), 0, buf
);
5946 LeaveCriticalSection( &freetype_cs
);
5950 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5956 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
5958 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5959 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
5963 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5965 /* FIXME: This doesn't match what Windows does: it does some fancy
5966 * things with duplicate glyph index to char code mappings, while
5967 * we just avoid overriding existing entries.
5969 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
5970 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
5972 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
5979 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
5980 for (n
= 0; n
<= 65535; n
++)
5981 glyph_to_char
[n
] = (USHORT
)n
;
5984 tt_kern_table
= buf
;
5985 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
5986 TRACE("version %u, nTables %u\n",
5987 GET_BE_WORD(tt_kern_table
->version
), nTables
);
5989 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
5991 for (i
= 0; i
< nTables
; i
++)
5993 struct TT_kern_subtable tt_kern_subtable_copy
;
5995 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
5996 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
5997 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
5999 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6000 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
6001 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
6003 /* According to the TrueType specification this is the only format
6004 * that will be properly interpreted by Windows and OS/2
6006 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
6008 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
6010 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6011 glyph_to_char
, NULL
, 0);
6012 font
->total_kern_pairs
+= new_chunk
;
6014 if (!font
->kern_pairs
)
6015 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
6016 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6018 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
6019 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6021 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6022 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
6025 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
6027 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
6030 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
6031 HeapFree(GetProcessHeap(), 0, buf
);
6033 if (cPairs
&& kern_pair
)
6035 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6036 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6037 LeaveCriticalSection( &freetype_cs
);
6040 LeaveCriticalSection( &freetype_cs
);
6041 return font
->total_kern_pairs
;
6044 #else /* HAVE_FREETYPE */
6046 /*************************************************************************/
6048 BOOL
WineEngInit(void)
6052 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
6056 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
6061 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6066 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
6067 LPWORD pgi
, DWORD flags
)
6072 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
6073 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
6076 ERR("called but we don't have FreeType\n");
6080 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6082 ERR("called but we don't have FreeType\n");
6086 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
6087 OUTLINETEXTMETRICW
*potm
)
6089 ERR("called but we don't have FreeType\n");
6093 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6096 ERR("called but we don't have FreeType\n");
6100 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6103 ERR("called but we don't have FreeType\n");
6107 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6110 ERR("called but we don't have FreeType\n");
6114 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6115 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6117 ERR("called but we don't have FreeType\n");
6121 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6122 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6124 ERR("called but we don't have FreeType\n");
6128 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6131 ERR("called but we don't have FreeType\n");
6135 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6137 ERR("called but we don't have FreeType\n");
6141 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6147 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6153 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
6159 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6162 return DEFAULT_CHARSET
;
6165 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6170 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6172 FIXME("(%p, %p): stub\n", font
, glyphset
);
6176 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6181 /*************************************************************************
6182 * GetRasterizerCaps (GDI32.@)
6184 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6186 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6188 lprs
->nLanguageID
= 0;
6192 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6194 ERR("called but we don't have FreeType\n");
6198 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6200 ERR("called but we don't have FreeType\n");
6204 #endif /* HAVE_FREETYPE */