2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
60 #undef GetCurrentThread
63 #undef GetCurrentProcess
76 #endif /* HAVE_CARBON_CARBON_H */
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font
);
93 #ifdef HAVE_FT2BUILD_H
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType
;
143 static FT_Library library
= 0;
150 static FT_Version_t FT_Version
;
151 static DWORD FT_SimpleVersion
;
153 static void *ft_handle
= NULL
;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit
);
157 MAKE_FUNCPTR(FT_Done_Face
);
158 MAKE_FUNCPTR(FT_Get_Char_Index
);
159 MAKE_FUNCPTR(FT_Get_Module
);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
163 MAKE_FUNCPTR(FT_Init_FreeType
);
164 MAKE_FUNCPTR(FT_Load_Glyph
);
165 MAKE_FUNCPTR(FT_Matrix_Multiply
);
166 MAKE_FUNCPTR(FT_MulFix
);
167 MAKE_FUNCPTR(FT_New_Face
);
168 MAKE_FUNCPTR(FT_New_Memory_Face
);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
170 MAKE_FUNCPTR(FT_Outline_Transform
);
171 MAKE_FUNCPTR(FT_Outline_Translate
);
172 MAKE_FUNCPTR(FT_Select_Charmap
);
173 MAKE_FUNCPTR(FT_Set_Charmap
);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
175 MAKE_FUNCPTR(FT_Vector_Transform
);
176 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
177 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
178 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
179 static FT_ULong (*pFT_Get_Next_Char
)(FT_Face
,FT_ULong
,FT_UInt
*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent
);
188 MAKE_FUNCPTR(FcFontList
);
189 MAKE_FUNCPTR(FcFontSetDestroy
);
190 MAKE_FUNCPTR(FcInit
);
191 MAKE_FUNCPTR(FcObjectSetAdd
);
192 MAKE_FUNCPTR(FcObjectSetCreate
);
193 MAKE_FUNCPTR(FcObjectSetDestroy
);
194 MAKE_FUNCPTR(FcPatternCreate
);
195 MAKE_FUNCPTR(FcPatternDestroy
);
196 MAKE_FUNCPTR(FcPatternGetBool
);
197 MAKE_FUNCPTR(FcPatternGetString
);
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
227 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
234 FT_Short internal_leading
;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
241 FT_Short height
, width
;
242 FT_Pos size
, x_ppem
, y_ppem
;
248 NEWTEXTMETRICEXW ntm
;
252 typedef struct tagFace
{
257 DWORD font_data_size
;
262 FONTSIGNATURE fs_links
;
263 DWORD ntmFlags
; /* Only some bits stored here. Others are computed on the fly */
264 FT_Fixed font_version
;
266 Bitmap_Size size
; /* set if face is a bitmap */
267 BOOL external
; /* TRUE if we should manually add this font to the registry */
268 struct tagFamily
*family
;
269 /* Cached data for Enum */
270 struct enum_data
*cached_enum_data
;
273 typedef struct tagFamily
{
275 const WCHAR
*FamilyName
;
281 INT adv
; /* These three hold to widths of the unrotated chars */
299 typedef struct tagHFONTLIST
{
314 struct list hfontlist
;
315 OUTLINETEXTMETRICW
*potm
;
316 DWORD total_kern_pairs
;
317 KERNINGPAIR
*kern_pairs
;
318 struct list child_fonts
;
320 /* the following members can be accessed without locking, they are never modified after creation */
322 struct font_mapping
*mapping
;
343 const WCHAR
*font_name
;
347 #define GM_BLOCK_SIZE 128
348 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
350 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
351 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
352 #define UNUSED_CACHE_SIZE 10
353 static struct list child_font_list
= LIST_INIT(child_font_list
);
354 static struct list system_links
= LIST_INIT(system_links
);
356 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
358 static struct list font_list
= LIST_INIT(font_list
);
360 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
361 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
362 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
364 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
366 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
367 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
368 'W','i','n','d','o','w','s','\\',
369 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
370 'F','o','n','t','s','\0'};
372 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
373 'W','i','n','d','o','w','s',' ','N','T','\\',
374 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
375 'F','o','n','t','s','\0'};
377 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
378 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
379 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
380 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
382 static const WCHAR
* const SystemFontValues
[4] = {
389 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
390 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
392 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
393 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
394 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
395 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
396 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
397 'E','u','r','o','p','e','a','n','\0'};
398 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
399 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
400 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
401 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
402 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
403 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
404 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
405 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
406 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
407 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
408 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
409 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
411 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
421 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
429 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
438 typedef struct tagFontSubst
{
454 static struct list mappings_list
= LIST_INIT( mappings_list
);
456 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
458 static CRITICAL_SECTION freetype_cs
;
459 static CRITICAL_SECTION_DEBUG critsect_debug
=
462 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
463 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
465 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
467 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
469 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
471 /****************************************
472 * Notes on .fon files
474 * The fonts System, FixedSys and Terminal are special. There are typically multiple
475 * versions installed for different resolutions and codepages. Windows stores which one to use
476 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
478 * FIXEDFON.FON FixedSys
480 * OEMFONT.FON Terminal
481 * LogPixels Current dpi set by the display control panel applet
482 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
483 * also has a LogPixels value that appears to mirror this)
485 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
486 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
487 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
488 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
489 * so that makes sense.
491 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
492 * to be mapped into the registry on Windows 2000 at least).
495 * ega80woa.fon=ega80850.fon
496 * ega40woa.fon=ega40850.fon
497 * cga80woa.fon=cga80850.fon
498 * cga40woa.fon=cga40850.fon
501 #ifdef HAVE_CARBON_CARBON_H
502 static char *find_cache_dir(void)
506 static char cached_path
[MAX_PATH
];
507 static const char *wine
= "/Wine", *fonts
= "/Fonts";
509 if(*cached_path
) return cached_path
;
511 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
514 WARN("can't create cached data folder\n");
517 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
520 WARN("can't create cached data path\n");
524 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
526 ERR("Could not create full path\n");
530 strcat(cached_path
, wine
);
532 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
534 WARN("Couldn't mkdir %s\n", cached_path
);
538 strcat(cached_path
, fonts
);
539 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
541 WARN("Couldn't mkdir %s\n", cached_path
);
548 /******************************************************************
551 * Extracts individual TrueType font files from a Mac suitcase font
552 * and saves them into the user's caches directory (see
554 * Returns a NULL terminated array of filenames.
556 * We do this because they are apps that try to read ttf files
557 * themselves and they don't like Mac suitcase files.
559 static char **expand_mac_font(const char *path
)
566 const char *filename
;
570 unsigned int size
, max_size
;
573 TRACE("path %s\n", path
);
575 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
578 WARN("failed to get ref\n");
582 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
585 TRACE("no data fork, so trying resource fork\n");
586 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
589 TRACE("unable to open resource fork\n");
596 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
599 CloseResFile(res_ref
);
603 out_dir
= find_cache_dir();
605 filename
= strrchr(path
, '/');
606 if(!filename
) filename
= path
;
609 /* output filename has the form out_dir/filename_%04x.ttf */
610 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
617 unsigned short *num_faces_ptr
, num_faces
, face
;
620 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
622 fond
= Get1IndResource(fond_res
, idx
);
624 TRACE("got fond resource %d\n", idx
);
627 fam_rec
= *(FamRec
**)fond
;
628 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
629 num_faces
= GET_BE_WORD(*num_faces_ptr
);
631 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
632 TRACE("num faces %04x\n", num_faces
);
633 for(face
= 0; face
< num_faces
; face
++, assoc
++)
636 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
637 unsigned short size
, font_id
;
640 size
= GET_BE_WORD(assoc
->fontSize
);
641 font_id
= GET_BE_WORD(assoc
->fontID
);
644 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
648 TRACE("trying to load sfnt id %04x\n", font_id
);
649 sfnt
= GetResource(sfnt_res
, font_id
);
652 TRACE("can't get sfnt resource %04x\n", font_id
);
656 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
661 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
663 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
664 if(fd
!= -1 || errno
== EEXIST
)
668 unsigned char *sfnt_data
;
671 sfnt_data
= *(unsigned char**)sfnt
;
672 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
676 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
679 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
681 ret
.array
[ret
.size
++] = output
;
685 WARN("unable to create %s\n", output
);
686 HeapFree(GetProcessHeap(), 0, output
);
689 ReleaseResource(sfnt
);
692 ReleaseResource(fond
);
695 CloseResFile(res_ref
);
700 #endif /* HAVE_CARBON_CARBON_H */
702 static inline BOOL
is_win9x(void)
704 return GetVersion() & 0x80000000;
707 This function builds an FT_Fixed from a float. It puts the integer part
708 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
709 It fails if the integer part of the float number is greater than SHORT_MAX.
711 static inline FT_Fixed
FT_FixedFromFloat(float f
)
714 unsigned short fract
= (f
- value
) * 0xFFFF;
715 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
719 This function builds an FT_Fixed from a FIXED. It simply put f.value
720 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
722 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
724 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
728 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
733 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
734 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
736 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
737 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
739 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
741 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
743 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
747 file
= strrchr(face
->file
, '/');
752 if(!strcasecmp(file
, file_nameA
))
754 HeapFree(GetProcessHeap(), 0, file_nameA
);
759 HeapFree(GetProcessHeap(), 0, file_nameA
);
763 static Family
*find_family_from_name(const WCHAR
*name
)
767 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
769 if(!strcmpiW(family
->FamilyName
, name
))
776 static void DumpSubstList(void)
780 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
782 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
783 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
784 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
786 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
787 debugstr_w(psub
->to
.name
));
792 static LPWSTR
strdupW(LPCWSTR p
)
795 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
796 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
801 static LPSTR
strdupA(LPCSTR p
)
804 DWORD len
= (strlen(p
) + 1);
805 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
810 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
815 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
817 if(!strcmpiW(element
->from
.name
, from_name
) &&
818 (element
->from
.charset
== from_charset
||
819 element
->from
.charset
== -1))
826 #define ADD_FONT_SUBST_FORCE 1
828 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
830 FontSubst
*from_exist
, *to_exist
;
832 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
834 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
836 list_remove(&from_exist
->entry
);
837 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
838 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
839 HeapFree(GetProcessHeap(), 0, from_exist
);
845 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
849 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
850 subst
->to
.name
= strdupW(to_exist
->to
.name
);
853 list_add_tail(subst_list
, &subst
->entry
);
858 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
859 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
860 HeapFree(GetProcessHeap(), 0, subst
);
864 static void split_subst_info(NameCs
*nc
, LPSTR str
)
866 CHAR
*p
= strrchr(str
, ',');
871 nc
->charset
= strtol(p
+1, NULL
, 10);
874 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
875 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
876 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
879 static void LoadSubstList(void)
883 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
887 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
888 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
889 &hkey
) == ERROR_SUCCESS
) {
891 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
892 &valuelen
, &datalen
, NULL
, NULL
);
894 valuelen
++; /* returned value doesn't include room for '\0' */
895 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
896 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
900 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
901 &dlen
) == ERROR_SUCCESS
) {
902 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
904 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
905 split_subst_info(&psub
->from
, value
);
906 split_subst_info(&psub
->to
, data
);
908 /* Win 2000 doesn't allow mapping between different charsets
909 or mapping of DEFAULT_CHARSET */
910 if((psub
->to
.charset
!= psub
->from
.charset
) ||
911 psub
->to
.charset
== DEFAULT_CHARSET
) {
912 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
913 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
914 HeapFree(GetProcessHeap(), 0, psub
);
916 add_font_subst(&font_subst_list
, psub
, 0);
918 /* reset dlen and vlen */
922 HeapFree(GetProcessHeap(), 0, data
);
923 HeapFree(GetProcessHeap(), 0, value
);
928 static WCHAR
*get_familyname(FT_Face ft_face
)
930 WCHAR
*family
= NULL
;
932 FT_UInt num_names
, name_index
, i
;
934 if(FT_IS_SFNT(ft_face
))
936 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
938 for(name_index
= 0; name_index
< num_names
; name_index
++)
940 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
942 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
943 (name
.language_id
== GetUserDefaultLCID()) &&
944 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
945 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
947 /* String is not nul terminated and string_len is a byte length. */
948 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
949 for(i
= 0; i
< name
.string_len
/ 2; i
++)
951 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
952 family
[i
] = GET_BE_WORD(*tmp
);
956 TRACE("Got localised name %s\n", debugstr_w(family
));
967 /*****************************************************************
970 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
971 * of FreeType that don't export this function.
974 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
979 /* If the FT_Load_Sfnt_Table function is there we'll use it */
980 if(pFT_Load_Sfnt_Table
)
982 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
984 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
985 else /* Do it the hard way */
987 TT_Face tt_face
= (TT_Face
) ft_face
;
988 SFNT_Interface
*sfnt
;
989 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
992 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
996 /* A field was added in the middle of the structure in 2.1.x */
997 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
999 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1007 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1008 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1009 "Please upgrade your freetype library.\n");
1012 err
= FT_Err_Unimplemented_Feature
;
1019 #define ADDFONT_EXTERNAL_FONT 0x01
1020 #define ADDFONT_FORCE_BITMAP 0x02
1021 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1025 TT_Header
*pHeader
= NULL
;
1026 WCHAR
*english_family
, *localised_family
, *StyleW
;
1030 struct list
*family_elem_ptr
, *face_elem_ptr
;
1032 FT_Long face_index
= 0, num_faces
;
1033 #ifdef HAVE_FREETYPE_FTWINFNT_H
1034 FT_WinFNT_HeaderRec winfnt_header
;
1036 int i
, bitmap_num
, internal_leading
;
1039 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1040 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1042 #ifdef HAVE_CARBON_CARBON_H
1043 if(file
&& !fake_family
)
1045 char **mac_list
= expand_mac_font(file
);
1048 BOOL had_one
= FALSE
;
1050 for(cursor
= mac_list
; *cursor
; cursor
++)
1053 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1054 HeapFree(GetProcessHeap(), 0, *cursor
);
1056 HeapFree(GetProcessHeap(), 0, mac_list
);
1061 #endif /* HAVE_CARBON_CARBON_H */
1064 char *family_name
= fake_family
;
1068 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1069 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1072 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1073 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1077 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1081 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*/
1082 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1083 pFT_Done_Face(ft_face
);
1087 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1088 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1089 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1090 pFT_Done_Face(ft_face
);
1094 if(FT_IS_SFNT(ft_face
))
1096 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1097 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1098 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1100 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1101 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1102 pFT_Done_Face(ft_face
);
1106 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1107 we don't want to load these. */
1108 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1112 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1114 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1115 pFT_Done_Face(ft_face
);
1121 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1122 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1123 pFT_Done_Face(ft_face
);
1129 localised_family
= get_familyname(ft_face
);
1130 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1132 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1133 HeapFree(GetProcessHeap(), 0, localised_family
);
1134 num_faces
= ft_face
->num_faces
;
1135 pFT_Done_Face(ft_face
);
1138 HeapFree(GetProcessHeap(), 0, localised_family
);
1142 family_name
= ft_face
->family_name
;
1146 My_FT_Bitmap_Size
*size
= NULL
;
1149 if(!FT_IS_SCALABLE(ft_face
))
1150 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1152 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1153 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1154 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1156 localised_family
= NULL
;
1158 localised_family
= get_familyname(ft_face
);
1159 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1160 HeapFree(GetProcessHeap(), 0, localised_family
);
1161 localised_family
= NULL
;
1166 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1167 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1168 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1173 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1174 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1175 list_init(&family
->faces
);
1176 list_add_tail(&font_list
, &family
->entry
);
1178 if(localised_family
) {
1179 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1180 subst
->from
.name
= strdupW(english_family
);
1181 subst
->from
.charset
= -1;
1182 subst
->to
.name
= strdupW(localised_family
);
1183 subst
->to
.charset
= -1;
1184 add_font_subst(&font_subst_list
, subst
, 0);
1187 HeapFree(GetProcessHeap(), 0, localised_family
);
1188 HeapFree(GetProcessHeap(), 0, english_family
);
1190 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1191 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1192 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1194 internal_leading
= 0;
1195 memset(&fs
, 0, sizeof(fs
));
1197 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1199 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1200 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1201 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1202 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1203 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1204 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1205 if(pOS2
->version
== 0) {
1208 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1209 fs
.fsCsb
[0] |= FS_LATIN1
;
1211 fs
.fsCsb
[0] |= FS_SYMBOL
;
1214 #ifdef HAVE_FREETYPE_FTWINFNT_H
1215 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1217 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1218 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1219 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1220 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
1221 internal_leading
= winfnt_header
.internal_leading
;
1225 face_elem_ptr
= list_head(&family
->faces
);
1226 while(face_elem_ptr
) {
1227 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1228 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1229 if(!strcmpW(face
->StyleName
, StyleW
) &&
1230 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1231 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1232 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1233 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1236 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1237 HeapFree(GetProcessHeap(), 0, StyleW
);
1238 pFT_Done_Face(ft_face
);
1241 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1242 TRACE("Original font is newer so skipping this one\n");
1243 HeapFree(GetProcessHeap(), 0, StyleW
);
1244 pFT_Done_Face(ft_face
);
1247 TRACE("Replacing original with this one\n");
1248 list_remove(&face
->entry
);
1249 HeapFree(GetProcessHeap(), 0, face
->file
);
1250 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1251 HeapFree(GetProcessHeap(), 0, face
);
1256 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1257 face
->cached_enum_data
= NULL
;
1258 list_add_tail(&family
->faces
, &face
->entry
);
1259 face
->StyleName
= StyleW
;
1262 face
->file
= strdupA(file
);
1263 face
->font_data_ptr
= NULL
;
1264 face
->font_data_size
= 0;
1269 face
->font_data_ptr
= font_data_ptr
;
1270 face
->font_data_size
= font_data_size
;
1272 face
->face_index
= face_index
;
1273 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
1274 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
1275 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1276 face
->family
= family
;
1277 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1278 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
1279 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1281 if(FT_IS_SCALABLE(ft_face
)) {
1282 memset(&face
->size
, 0, sizeof(face
->size
));
1283 face
->scalable
= TRUE
;
1285 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1286 size
->height
, size
->width
, size
->size
>> 6,
1287 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1288 face
->size
.height
= size
->height
;
1289 face
->size
.width
= size
->width
;
1290 face
->size
.size
= size
->size
;
1291 face
->size
.x_ppem
= size
->x_ppem
;
1292 face
->size
.y_ppem
= size
->y_ppem
;
1293 face
->size
.internal_leading
= internal_leading
;
1294 face
->scalable
= FALSE
;
1297 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1299 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1301 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1302 face
->ntmFlags
= NTM_PS_OPENTYPE
;
1307 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1308 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1309 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1310 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1313 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1314 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1315 switch(ft_face
->charmaps
[i
]->encoding
) {
1316 case FT_ENCODING_UNICODE
:
1317 case FT_ENCODING_APPLE_ROMAN
:
1318 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1320 case FT_ENCODING_MS_SYMBOL
:
1321 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1329 if (!(face
->fs
.fsCsb
[0] & FS_SYMBOL
))
1330 have_installed_roman_font
= TRUE
;
1331 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1333 num_faces
= ft_face
->num_faces
;
1334 pFT_Done_Face(ft_face
);
1335 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1336 debugstr_w(StyleW
));
1337 } while(num_faces
> ++face_index
);
1341 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1343 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1346 static void DumpFontList(void)
1350 struct list
*family_elem_ptr
, *face_elem_ptr
;
1352 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1353 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1354 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1355 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1356 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1357 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1359 TRACE(" %d", face
->size
.height
);
1366 /***********************************************************
1367 * The replacement list is a way to map an entire font
1368 * family onto another family. For example adding
1370 * [HKCU\Software\Wine\Fonts\Replacements]
1371 * "Wingdings"="Winedings"
1373 * would enumerate the Winedings font both as Winedings and
1374 * Wingdings. However if a real Wingdings font is present the
1375 * replacement does not take place.
1378 static void LoadReplaceList(void)
1381 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1386 struct list
*family_elem_ptr
, *face_elem_ptr
;
1389 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1390 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1392 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1393 &valuelen
, &datalen
, NULL
, NULL
);
1395 valuelen
++; /* returned value doesn't include room for '\0' */
1396 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1397 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1401 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1402 &dlen
) == ERROR_SUCCESS
) {
1403 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1404 /* "NewName"="Oldname" */
1405 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1407 /* Find the old family and hence all of the font files
1409 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1410 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1411 if(!strcmpiW(family
->FamilyName
, data
)) {
1412 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1413 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1414 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1415 debugstr_w(face
->StyleName
), familyA
);
1416 /* Now add a new entry with the new family name */
1417 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1422 /* reset dlen and vlen */
1426 HeapFree(GetProcessHeap(), 0, data
);
1427 HeapFree(GetProcessHeap(), 0, value
);
1432 /*************************************************************
1435 static BOOL
init_system_links(void)
1437 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1438 'W','i','n','d','o','w','s',' ','N','T','\\',
1439 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1440 'S','y','s','t','e','m','L','i','n','k',0};
1443 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1444 WCHAR
*value
, *data
;
1445 WCHAR
*entry
, *next
;
1446 SYSTEM_LINKS
*font_link
, *system_font_link
;
1447 CHILD_FONT
*child_font
;
1448 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1449 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1450 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1456 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1458 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1459 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1460 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1461 val_len
= max_val
+ 1;
1462 data_len
= max_data
;
1464 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1466 TRACE("%s:\n", debugstr_w(value
));
1468 memset(&fs
, 0, sizeof(fs
));
1469 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1470 psub
= get_font_subst(&font_subst_list
, value
, -1);
1471 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1472 list_init(&font_link
->links
);
1473 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1476 CHILD_FONT
*child_font
;
1478 TRACE("\t%s\n", debugstr_w(entry
));
1480 next
= entry
+ strlenW(entry
) + 1;
1482 face_name
= strchrW(entry
, ',');
1486 while(isspaceW(*face_name
))
1489 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1491 face_name
= psub
->to
.name
;
1493 face
= find_face_from_filename(entry
, face_name
);
1496 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1500 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1501 child_font
->face
= face
;
1502 child_font
->font
= NULL
;
1503 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1504 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1505 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1506 list_add_tail(&font_link
->links
, &child_font
->entry
);
1508 family
= find_family_from_name(font_link
->font_name
);
1511 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1513 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
1516 list_add_tail(&system_links
, &font_link
->entry
);
1517 val_len
= max_val
+ 1;
1518 data_len
= max_data
;
1521 HeapFree(GetProcessHeap(), 0, value
);
1522 HeapFree(GetProcessHeap(), 0, data
);
1526 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1529 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1530 system_font_link
->font_name
= strdupW(System
);
1531 list_init(&system_font_link
->links
);
1533 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1536 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1537 child_font
->face
= face
;
1538 child_font
->font
= NULL
;
1539 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1540 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1542 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1544 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1546 CHILD_FONT
*font_link_entry
;
1547 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1549 CHILD_FONT
*new_child
;
1550 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1551 new_child
->face
= font_link_entry
->face
;
1552 new_child
->font
= NULL
;
1553 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1558 list_add_tail(&system_links
, &system_font_link
->entry
);
1562 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1565 struct dirent
*dent
;
1566 char path
[MAX_PATH
];
1568 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1570 dir
= opendir(dirname
);
1572 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1575 while((dent
= readdir(dir
)) != NULL
) {
1576 struct stat statbuf
;
1578 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1581 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1583 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1585 if(stat(path
, &statbuf
) == -1)
1587 WARN("Can't stat %s\n", debugstr_a(path
));
1590 if(S_ISDIR(statbuf
.st_mode
))
1591 ReadFontDir(path
, external_fonts
);
1593 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1599 static void load_fontconfig_fonts(void)
1601 #ifdef SONAME_LIBFONTCONFIG
1602 void *fc_handle
= NULL
;
1611 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1613 TRACE("Wine cannot find the fontconfig library (%s).\n",
1614 SONAME_LIBFONTCONFIG
);
1617 #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;}
1618 LOAD_FUNCPTR(FcConfigGetCurrent
);
1619 LOAD_FUNCPTR(FcFontList
);
1620 LOAD_FUNCPTR(FcFontSetDestroy
);
1621 LOAD_FUNCPTR(FcInit
);
1622 LOAD_FUNCPTR(FcObjectSetAdd
);
1623 LOAD_FUNCPTR(FcObjectSetCreate
);
1624 LOAD_FUNCPTR(FcObjectSetDestroy
);
1625 LOAD_FUNCPTR(FcPatternCreate
);
1626 LOAD_FUNCPTR(FcPatternDestroy
);
1627 LOAD_FUNCPTR(FcPatternGetBool
);
1628 LOAD_FUNCPTR(FcPatternGetString
);
1631 if(!pFcInit()) return;
1633 config
= pFcConfigGetCurrent();
1634 pat
= pFcPatternCreate();
1635 os
= pFcObjectSetCreate();
1636 pFcObjectSetAdd(os
, FC_FILE
);
1637 pFcObjectSetAdd(os
, FC_SCALABLE
);
1638 fontset
= pFcFontList(config
, pat
, os
);
1639 if(!fontset
) return;
1640 for(i
= 0; i
< fontset
->nfont
; i
++) {
1643 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1645 TRACE("fontconfig: %s\n", file
);
1647 /* We're just interested in OT/TT fonts for now, so this hack just
1648 picks up the scalable fonts without extensions .pf[ab] to save time
1649 loading every other font */
1651 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1653 TRACE("not scalable\n");
1657 len
= strlen( file
);
1658 if(len
< 4) continue;
1659 ext
= &file
[ len
- 3 ];
1660 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1661 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1663 pFcFontSetDestroy(fontset
);
1664 pFcObjectSetDestroy(os
);
1665 pFcPatternDestroy(pat
);
1671 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1674 const char *data_dir
= wine_get_data_dir();
1676 if (!data_dir
) data_dir
= wine_get_build_dir();
1683 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1685 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1687 strcpy(unix_name
, data_dir
);
1688 strcat(unix_name
, "/fonts/");
1690 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1692 EnterCriticalSection( &freetype_cs
);
1693 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1694 LeaveCriticalSection( &freetype_cs
);
1695 HeapFree(GetProcessHeap(), 0, unix_name
);
1700 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1702 static const WCHAR slashW
[] = {'\\','\0'};
1704 WCHAR windowsdir
[MAX_PATH
];
1707 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1708 strcatW(windowsdir
, fontsW
);
1709 strcatW(windowsdir
, slashW
);
1710 strcatW(windowsdir
, file
);
1711 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1712 EnterCriticalSection( &freetype_cs
);
1713 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1714 LeaveCriticalSection( &freetype_cs
);
1715 HeapFree(GetProcessHeap(), 0, unixname
);
1720 static void load_system_fonts(void)
1723 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1724 const WCHAR
* const *value
;
1726 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1729 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1730 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1731 strcatW(windowsdir
, fontsW
);
1732 for(value
= SystemFontValues
; *value
; value
++) {
1733 dlen
= sizeof(data
);
1734 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1738 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1739 if((unixname
= wine_get_unix_file_name(pathW
))) {
1740 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1741 HeapFree(GetProcessHeap(), 0, unixname
);
1744 load_font_from_data_dir(data
);
1751 /*************************************************************
1753 * This adds registry entries for any externally loaded fonts
1754 * (fonts from fontconfig or FontDirs). It also deletes entries
1755 * of no longer existing fonts.
1758 static void update_reg_entries(void)
1760 HKEY winkey
= 0, externalkey
= 0;
1763 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
1766 struct list
*family_elem_ptr
, *face_elem_ptr
;
1768 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1769 static const WCHAR spaceW
[] = {' ', '\0'};
1772 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1773 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
1774 ERR("Can't create Windows font reg key\n");
1777 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1778 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
1779 ERR("Can't create external font reg key\n");
1783 /* Delete all external fonts added last time */
1785 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1786 &valuelen
, &datalen
, NULL
, NULL
);
1787 valuelen
++; /* returned value doesn't include room for '\0' */
1788 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1789 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1791 dlen
= datalen
* sizeof(WCHAR
);
1794 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1795 &dlen
) == ERROR_SUCCESS
) {
1797 RegDeleteValueW(winkey
, valueW
);
1798 /* reset dlen and vlen */
1802 HeapFree(GetProcessHeap(), 0, data
);
1803 HeapFree(GetProcessHeap(), 0, valueW
);
1805 /* Delete the old external fonts key */
1806 RegCloseKey(externalkey
);
1808 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1810 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1811 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1812 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
1813 ERR("Can't create external font reg key\n");
1817 /* enumerate the fonts and add external ones to the two keys */
1819 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1820 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1821 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1822 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1823 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1824 if(!face
->external
) continue;
1826 if(strcmpiW(face
->StyleName
, RegularW
))
1827 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1828 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1829 strcpyW(valueW
, family
->FamilyName
);
1830 if(len
!= len_fam
) {
1831 strcatW(valueW
, spaceW
);
1832 strcatW(valueW
, face
->StyleName
);
1834 strcatW(valueW
, TrueType
);
1835 if((path
= strrchr(face
->file
, '/')) == NULL
)
1839 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1841 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1842 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1843 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1844 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1846 HeapFree(GetProcessHeap(), 0, file
);
1847 HeapFree(GetProcessHeap(), 0, valueW
);
1852 RegCloseKey(externalkey
);
1854 RegCloseKey(winkey
);
1859 /*************************************************************
1860 * WineEngAddFontResourceEx
1863 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1866 if (ft_handle
) /* do it only if we have freetype up and running */
1871 FIXME("Ignoring flags %x\n", flags
);
1873 if((unixname
= wine_get_unix_file_name(file
)))
1875 EnterCriticalSection( &freetype_cs
);
1876 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1877 LeaveCriticalSection( &freetype_cs
);
1878 HeapFree(GetProcessHeap(), 0, unixname
);
1880 if (!ret
&& !strchrW(file
, '\\')) {
1881 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
1882 ret
= load_font_from_winfonts_dir(file
);
1884 /* Try in datadir/fonts (or builddir/fonts),
1885 * needed for Magic the Gathering Online
1887 ret
= load_font_from_data_dir(file
);
1894 /*************************************************************
1895 * WineEngAddFontMemResourceEx
1898 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
1900 if (ft_handle
) /* do it only if we have freetype up and running */
1902 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
1904 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
1905 memcpy(pFontCopy
, pbFont
, cbFont
);
1907 EnterCriticalSection( &freetype_cs
);
1908 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1909 LeaveCriticalSection( &freetype_cs
);
1913 TRACE("AddFontToList failed\n");
1914 HeapFree(GetProcessHeap(), 0, pFontCopy
);
1917 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1918 * For now return something unique but quite random
1920 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
1921 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
1928 /*************************************************************
1929 * WineEngRemoveFontResourceEx
1932 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1938 static const struct nls_update_font_list
1940 UINT ansi_cp
, oem_cp
;
1941 const char *oem
, *fixed
, *system
;
1942 const char *courier
, *serif
, *small
, *sserif
;
1943 /* these are for font substitute */
1944 const char *shelldlg
, *tmsrmn
;
1945 } nls_update_font_list
[] =
1947 /* Latin 1 (United States) */
1948 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1949 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1950 "Tahoma","Times New Roman",
1952 /* Latin 1 (Multilingual) */
1953 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1954 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1955 "Tahoma","Times New Roman", /* FIXME unverified */
1957 /* Eastern Europe */
1958 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1959 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1960 "Tahoma","Times New Roman", /* FIXME unverified */
1963 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1964 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1965 "Tahoma","Times New Roman", /* FIXME unverified */
1968 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1969 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1970 "Tahoma","Times New Roman", /* FIXME unverified */
1973 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1974 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1975 "Tahoma","Times New Roman", /* FIXME unverified */
1978 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1979 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1980 "Tahoma","Times New Roman", /* FIXME unverified */
1983 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1984 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1985 "Tahoma","Times New Roman", /* FIXME unverified */
1988 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1989 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1990 "Tahoma","Times New Roman", /* FIXME unverified */
1993 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1994 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1995 "Tahoma","Times New Roman", /* FIXME unverified */
1998 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1999 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2000 "Tahoma","Times New Roman", /* FIXME unverified */
2003 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2004 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2005 "MS UI Gothic","MS Serif",
2007 /* Chinese Simplified */
2008 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2009 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2010 "Tahoma", "Times New Roman", /* FIXME unverified */
2013 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2014 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2017 /* Chinese Traditional */
2018 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2019 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2020 "PMingLiU", "MingLiU",
2024 static inline HKEY
create_fonts_NT_registry_key(void)
2028 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2029 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2033 static inline HKEY
create_fonts_9x_registry_key(void)
2037 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2038 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2042 static inline HKEY
create_config_fonts_registry_key(void)
2046 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2047 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2051 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2053 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2054 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2055 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2056 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2059 static void update_font_info(void)
2061 char buf
[40], cpbuf
[40];
2064 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2066 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2069 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2070 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2071 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2072 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2073 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2076 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2078 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2083 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2085 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2087 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2090 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2092 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2093 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2097 hkey
= create_config_fonts_registry_key();
2098 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2099 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2100 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2103 hkey
= create_fonts_NT_registry_key();
2104 add_font_list(hkey
, &nls_update_font_list
[i
]);
2107 hkey
= create_fonts_9x_registry_key();
2108 add_font_list(hkey
, &nls_update_font_list
[i
]);
2111 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2113 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2114 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2115 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2116 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2122 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2125 /*************************************************************
2128 * Initialize FreeType library and create a list of available faces
2130 BOOL
WineEngInit(void)
2132 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2133 static const WCHAR pathW
[] = {'P','a','t','h',0};
2135 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2137 WCHAR windowsdir
[MAX_PATH
];
2140 const char *data_dir
;
2144 /* update locale dependent font info in registry */
2147 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2150 "Wine cannot find the FreeType font library. To enable Wine to\n"
2151 "use TrueType fonts please install a version of FreeType greater than\n"
2152 "or equal to 2.0.5.\n"
2153 "http://www.freetype.org\n");
2157 #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;}
2159 LOAD_FUNCPTR(FT_Vector_Unit
)
2160 LOAD_FUNCPTR(FT_Done_Face
)
2161 LOAD_FUNCPTR(FT_Get_Char_Index
)
2162 LOAD_FUNCPTR(FT_Get_Module
)
2163 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2164 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2165 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2166 LOAD_FUNCPTR(FT_Init_FreeType
)
2167 LOAD_FUNCPTR(FT_Load_Glyph
)
2168 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2169 LOAD_FUNCPTR(FT_MulFix
)
2170 LOAD_FUNCPTR(FT_New_Face
)
2171 LOAD_FUNCPTR(FT_New_Memory_Face
)
2172 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2173 LOAD_FUNCPTR(FT_Outline_Transform
)
2174 LOAD_FUNCPTR(FT_Outline_Translate
)
2175 LOAD_FUNCPTR(FT_Select_Charmap
)
2176 LOAD_FUNCPTR(FT_Set_Charmap
)
2177 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2178 LOAD_FUNCPTR(FT_Vector_Transform
)
2181 /* Don't warn if this one is missing */
2182 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2183 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2184 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2185 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2186 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2187 #ifdef HAVE_FREETYPE_FTWINFNT_H
2188 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2190 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2191 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2192 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2193 <= 2.0.3 has FT_Sqrt64 */
2197 if(pFT_Init_FreeType(&library
) != 0) {
2198 ERR("Can't init FreeType library\n");
2199 wine_dlclose(ft_handle
, NULL
, 0);
2203 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
2204 if (pFT_Library_Version
)
2206 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2208 if (FT_Version
.major
<=0)
2214 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2215 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2216 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2217 ((FT_Version
.patch
) & 0x0000ff);
2219 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2220 ERR("Failed to create font mutex\n");
2223 WaitForSingleObject(font_mutex
, INFINITE
);
2225 /* load the system bitmap fonts */
2226 load_system_fonts();
2228 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2229 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2230 strcatW(windowsdir
, fontsW
);
2231 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2233 ReadFontDir(unixname
, FALSE
);
2234 HeapFree(GetProcessHeap(), 0, unixname
);
2237 /* load the system truetype fonts */
2238 data_dir
= wine_get_data_dir();
2239 if (!data_dir
) data_dir
= wine_get_build_dir();
2240 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2241 strcpy(unixname
, data_dir
);
2242 strcat(unixname
, "/fonts/");
2243 ReadFontDir(unixname
, TRUE
);
2244 HeapFree(GetProcessHeap(), 0, unixname
);
2247 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2248 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2249 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2251 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2252 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2253 &hkey
) == ERROR_SUCCESS
) {
2255 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2256 &valuelen
, &datalen
, NULL
, NULL
);
2258 valuelen
++; /* returned value doesn't include room for '\0' */
2259 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2260 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2263 dlen
= datalen
* sizeof(WCHAR
);
2265 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2266 &dlen
) == ERROR_SUCCESS
) {
2267 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2269 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2271 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2272 HeapFree(GetProcessHeap(), 0, unixname
);
2275 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2277 WCHAR pathW
[MAX_PATH
];
2278 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2281 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2282 if((unixname
= wine_get_unix_file_name(pathW
)))
2284 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2285 HeapFree(GetProcessHeap(), 0, unixname
);
2288 load_font_from_data_dir(data
);
2290 /* reset dlen and vlen */
2295 HeapFree(GetProcessHeap(), 0, data
);
2296 HeapFree(GetProcessHeap(), 0, valueW
);
2300 load_fontconfig_fonts();
2302 /* then look in any directories that we've specified in the config file */
2303 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2304 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2310 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2312 len
+= sizeof(WCHAR
);
2313 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2314 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2316 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2317 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2318 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2319 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2323 LPSTR next
= strchr( ptr
, ':' );
2324 if (next
) *next
++ = 0;
2325 ReadFontDir( ptr
, TRUE
);
2328 HeapFree( GetProcessHeap(), 0, valueA
);
2330 HeapFree( GetProcessHeap(), 0, valueW
);
2339 update_reg_entries();
2341 init_system_links();
2343 ReleaseMutex(font_mutex
);
2347 "Wine cannot find certain functions that it needs inside the FreeType\n"
2348 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2349 "FreeType to at least version 2.0.5.\n"
2350 "http://www.freetype.org\n");
2351 wine_dlclose(ft_handle
, NULL
, 0);
2357 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2360 TT_HoriHeader
*pHori
;
2364 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2365 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2367 if(height
== 0) height
= 16;
2369 /* Calc. height of EM square:
2371 * For +ve lfHeight we have
2372 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2373 * Re-arranging gives:
2374 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2376 * For -ve lfHeight we have
2378 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2379 * with il = winAscent + winDescent - units_per_em]
2384 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2385 ppem
= ft_face
->units_per_EM
* height
/
2386 (pHori
->Ascender
- pHori
->Descender
);
2388 ppem
= ft_face
->units_per_EM
* height
/
2389 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2397 static struct font_mapping
*map_font_file( const char *name
)
2399 struct font_mapping
*mapping
;
2403 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2404 if (fstat( fd
, &st
) == -1) goto error
;
2406 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2408 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2410 mapping
->refcount
++;
2415 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2418 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2421 if (mapping
->data
== MAP_FAILED
)
2423 HeapFree( GetProcessHeap(), 0, mapping
);
2426 mapping
->refcount
= 1;
2427 mapping
->dev
= st
.st_dev
;
2428 mapping
->ino
= st
.st_ino
;
2429 mapping
->size
= st
.st_size
;
2430 list_add_tail( &mappings_list
, &mapping
->entry
);
2438 static void unmap_font_file( struct font_mapping
*mapping
)
2440 if (!--mapping
->refcount
)
2442 list_remove( &mapping
->entry
);
2443 munmap( mapping
->data
, mapping
->size
);
2444 HeapFree( GetProcessHeap(), 0, mapping
);
2448 static LONG
load_VDMX(GdiFont
*, LONG
);
2450 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2457 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2461 if (!(font
->mapping
= map_font_file( face
->file
)))
2463 WARN("failed to map %s\n", debugstr_a(face
->file
));
2466 data_ptr
= font
->mapping
->data
;
2467 data_size
= font
->mapping
->size
;
2471 data_ptr
= face
->font_data_ptr
;
2472 data_size
= face
->font_data_size
;
2475 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2477 ERR("FT_New_Face rets %d\n", err
);
2481 /* set it here, as load_VDMX needs it */
2482 font
->ft_face
= ft_face
;
2484 if(FT_IS_SCALABLE(ft_face
)) {
2485 /* load the VDMX table if we have one */
2486 font
->ppem
= load_VDMX(font
, height
);
2488 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2490 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2491 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2493 font
->ppem
= height
;
2494 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2495 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2501 static int get_nearest_charset(Face
*face
, int *cp
)
2503 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2504 a single face with the requested charset. The idea is to check if
2505 the selected font supports the current ANSI codepage, if it does
2506 return the corresponding charset, else return the first charset */
2509 int acp
= GetACP(), i
;
2513 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2514 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2515 return csi
.ciCharset
;
2517 for(i
= 0; i
< 32; i
++) {
2519 if(face
->fs
.fsCsb
[0] & fs0
) {
2520 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2522 return csi
.ciCharset
;
2525 FIXME("TCI failing on %x\n", fs0
);
2529 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2530 face
->fs
.fsCsb
[0], face
->file
);
2532 return DEFAULT_CHARSET
;
2535 static GdiFont
*alloc_font(void)
2537 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2539 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2540 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2542 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2543 ret
->total_kern_pairs
= (DWORD
)-1;
2544 ret
->kern_pairs
= NULL
;
2545 list_init(&ret
->hfontlist
);
2546 list_init(&ret
->child_fonts
);
2550 static void free_font(GdiFont
*font
)
2552 struct list
*cursor
, *cursor2
;
2555 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2557 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2558 struct list
*first_hfont
;
2559 HFONTLIST
*hfontlist
;
2560 list_remove(cursor
);
2563 first_hfont
= list_head(&child
->font
->hfontlist
);
2564 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2565 DeleteObject(hfontlist
->hfont
);
2566 HeapFree(GetProcessHeap(), 0, hfontlist
);
2567 free_font(child
->font
);
2569 HeapFree(GetProcessHeap(), 0, child
);
2572 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2573 if (font
->mapping
) unmap_font_file( font
->mapping
);
2574 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2575 HeapFree(GetProcessHeap(), 0, font
->potm
);
2576 HeapFree(GetProcessHeap(), 0, font
->name
);
2577 for (i
= 0; i
< font
->gmsize
; i
++)
2578 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2579 HeapFree(GetProcessHeap(), 0, font
->gm
);
2580 HeapFree(GetProcessHeap(), 0, font
);
2584 /*************************************************************
2587 * load the vdmx entry for the specified height
2590 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2591 ( ( (FT_ULong)_x4 << 24 ) | \
2592 ( (FT_ULong)_x3 << 16 ) | \
2593 ( (FT_ULong)_x2 << 8 ) | \
2596 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2611 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2615 BYTE devXRatio
, devYRatio
;
2616 USHORT numRecs
, numRatios
;
2617 DWORD result
, offset
= -1;
2621 /* For documentation on VDMX records, see
2622 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2625 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2627 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2630 /* FIXME: need the real device aspect ratio */
2634 numRecs
= GET_BE_WORD(hdr
[1]);
2635 numRatios
= GET_BE_WORD(hdr
[2]);
2637 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2638 for(i
= 0; i
< numRatios
; i
++) {
2641 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2642 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2645 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2647 if((ratio
.xRatio
== 0 &&
2648 ratio
.yStartRatio
== 0 &&
2649 ratio
.yEndRatio
== 0) ||
2650 (devXRatio
== ratio
.xRatio
&&
2651 devYRatio
>= ratio
.yStartRatio
&&
2652 devYRatio
<= ratio
.yEndRatio
))
2654 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2655 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2656 offset
= GET_BE_WORD(tmp
);
2662 FIXME("No suitable ratio found\n");
2666 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2668 BYTE startsz
, endsz
;
2671 recs
= GET_BE_WORD(group
.recs
);
2672 startsz
= group
.startsz
;
2673 endsz
= group
.endsz
;
2675 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2677 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2678 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2679 if(result
== GDI_ERROR
) {
2680 FIXME("Failed to retrieve vTable\n");
2685 for(i
= 0; i
< recs
; i
++) {
2686 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2687 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2688 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2690 if(yMax
+ -yMin
== height
) {
2693 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2696 if(yMax
+ -yMin
> height
) {
2699 goto end
; /* failed */
2701 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2702 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2703 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2704 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2710 TRACE("ppem not found for height %d\n", height
);
2714 if(ppem
< startsz
|| ppem
> endsz
)
2717 for(i
= 0; i
< recs
; i
++) {
2719 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2721 if(yPelHeight
> ppem
)
2724 if(yPelHeight
== ppem
) {
2725 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2726 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2727 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2733 HeapFree(GetProcessHeap(), 0, vTable
);
2739 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
2741 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2742 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2743 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2744 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2745 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2748 static void calc_hash(FONT_DESC
*pfd
)
2750 DWORD hash
= 0, *ptr
, two_chars
;
2754 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2756 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2758 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2760 pwc
= (WCHAR
*)&two_chars
;
2762 *pwc
= toupperW(*pwc
);
2764 *pwc
= toupperW(*pwc
);
2768 hash
^= !pfd
->can_use_bitmap
;
2773 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2778 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2780 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
2781 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2782 fd
.can_use_bitmap
= can_use_bitmap
;
2785 /* try the in-use list */
2786 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2787 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2788 if(!fontcmp(ret
, &fd
)) {
2789 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2790 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2791 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2792 if(hflist
->hfont
== hfont
)
2795 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2796 hflist
->hfont
= hfont
;
2797 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2802 /* then the unused list */
2803 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2804 while(font_elem_ptr
) {
2805 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2806 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2807 if(!fontcmp(ret
, &fd
)) {
2808 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2809 assert(list_empty(&ret
->hfontlist
));
2810 TRACE("Found %p in unused list\n", ret
);
2811 list_remove(&ret
->entry
);
2812 list_add_head(&gdi_font_list
, &ret
->entry
);
2813 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2814 hflist
->hfont
= hfont
;
2815 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2823 /*************************************************************
2824 * create_child_font_list
2826 static BOOL
create_child_font_list(GdiFont
*font
)
2829 SYSTEM_LINKS
*font_link
;
2830 CHILD_FONT
*font_link_entry
, *new_child
;
2832 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2834 if(!strcmpW(font_link
->font_name
, font
->name
))
2836 TRACE("found entry in system list\n");
2837 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2839 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2840 new_child
->face
= font_link_entry
->face
;
2841 new_child
->font
= NULL
;
2842 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2843 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
2853 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2855 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2857 if (pFT_Set_Charmap
)
2860 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2862 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2864 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2866 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2868 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2869 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2871 switch (ft_face
->charmaps
[i
]->platform_id
)
2874 cmap_def
= ft_face
->charmaps
[i
];
2876 case 0: /* Apple Unicode */
2877 cmap0
= ft_face
->charmaps
[i
];
2879 case 1: /* Macintosh */
2880 cmap1
= ft_face
->charmaps
[i
];
2883 cmap2
= ft_face
->charmaps
[i
];
2885 case 3: /* Microsoft */
2886 cmap3
= ft_face
->charmaps
[i
];
2891 if (cmap3
) /* prefer Microsoft cmap table */
2892 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2894 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2896 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2898 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2900 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2902 return ft_err
== FT_Err_Ok
;
2905 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
2908 /*************************************************************
2909 * WineEngCreateFontInstance
2912 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2915 Face
*face
, *best
, *best_bitmap
;
2916 Family
*family
, *last_resort_family
;
2917 struct list
*family_elem_ptr
, *face_elem_ptr
;
2918 INT height
, width
= 0;
2919 unsigned int score
= 0, new_score
;
2920 signed int diff
= 0, newdiff
;
2921 BOOL bd
, it
, can_use_bitmap
;
2926 EnterCriticalSection( &freetype_cs
);
2928 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2930 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2931 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2932 if(hflist
->hfont
== hfont
)
2934 LeaveCriticalSection( &freetype_cs
);
2939 if (!GetObjectW( hfont
, sizeof(lf
), &lf
))
2941 LeaveCriticalSection( &freetype_cs
);
2944 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2946 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2947 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2948 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2951 /* check the cache first */
2952 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2953 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2954 LeaveCriticalSection( &freetype_cs
);
2958 TRACE("not in cache\n");
2959 if(list_empty(&font_list
)) /* No fonts installed */
2961 TRACE("No fonts installed\n");
2962 LeaveCriticalSection( &freetype_cs
);
2965 if(!have_installed_roman_font
)
2967 TRACE("No roman font installed\n");
2968 LeaveCriticalSection( &freetype_cs
);
2974 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
2975 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
2976 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
2977 calc_hash(&ret
->font_desc
);
2978 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2979 hflist
->hfont
= hfont
;
2980 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2983 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2984 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2985 original value lfCharSet. Note this is a special case for
2986 Symbol and doesn't happen at least for "Wingdings*" */
2988 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
2989 lf
.lfCharSet
= SYMBOL_CHARSET
;
2991 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
2992 switch(lf
.lfCharSet
) {
2993 case DEFAULT_CHARSET
:
2994 csi
.fs
.fsCsb
[0] = 0;
2997 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
2998 csi
.fs
.fsCsb
[0] = 0;
3004 if(lf
.lfFaceName
[0] != '\0') {
3006 SYSTEM_LINKS
*font_link
;
3007 CHILD_FONT
*font_link_entry
;
3009 psub
= get_font_subst(&font_subst_list
, lf
.lfFaceName
, lf
.lfCharSet
);
3012 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
3013 debugstr_w(psub
->to
.name
));
3014 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3017 /* We want a match on name and charset or just name if
3018 charset was DEFAULT_CHARSET. If the latter then
3019 we fixup the returned charset later in get_nearest_charset
3020 where we'll either use the charset of the current ansi codepage
3021 or if that's unavailable the first charset that the font supports.
3023 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3024 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3025 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3026 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3027 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3028 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3029 if(face
->scalable
|| can_use_bitmap
)
3036 * Try check the SystemLink list first for a replacement font.
3037 * We may find good replacements there.
3039 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3041 if(!strcmpiW(font_link
->font_name
, lf
.lfFaceName
))
3043 TRACE("found entry in system list\n");
3044 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3046 face
= font_link_entry
->face
;
3047 family
= face
->family
;
3048 if(csi
.fs
.fsCsb
[0] &
3049 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3051 if(face
->scalable
|| can_use_bitmap
)
3059 /* If requested charset was DEFAULT_CHARSET then try using charset
3060 corresponding to the current ansi codepage */
3061 if(!csi
.fs
.fsCsb
[0]) {
3063 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3064 FIXME("TCI failed on codepage %d\n", acp
);
3065 csi
.fs
.fsCsb
[0] = 0;
3067 lf
.lfCharSet
= csi
.ciCharset
;
3070 /* Face families are in the top 4 bits of lfPitchAndFamily,
3071 so mask with 0xF0 before testing */
3073 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3074 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3075 strcpyW(lf
.lfFaceName
, defFixed
);
3076 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3077 strcpyW(lf
.lfFaceName
, defSerif
);
3078 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3079 strcpyW(lf
.lfFaceName
, defSans
);
3081 strcpyW(lf
.lfFaceName
, defSans
);
3082 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3083 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3084 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3085 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3086 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3087 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3088 if(face
->scalable
|| can_use_bitmap
)
3094 last_resort_family
= NULL
;
3095 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3096 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3097 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3098 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3099 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3102 if(can_use_bitmap
&& !last_resort_family
)
3103 last_resort_family
= family
;
3108 if(last_resort_family
) {
3109 family
= last_resort_family
;
3110 csi
.fs
.fsCsb
[0] = 0;
3114 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3115 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3116 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3117 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3118 if(face
->scalable
) {
3119 csi
.fs
.fsCsb
[0] = 0;
3120 WARN("just using first face for now\n");
3123 if(can_use_bitmap
&& !last_resort_family
)
3124 last_resort_family
= family
;
3127 if(!last_resort_family
) {
3128 FIXME("can't find a single appropriate font - bailing\n");
3130 LeaveCriticalSection( &freetype_cs
);
3134 WARN("could only find a bitmap font - this will probably look awful!\n");
3135 family
= last_resort_family
;
3136 csi
.fs
.fsCsb
[0] = 0;
3139 it
= lf
.lfItalic
? 1 : 0;
3140 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3142 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
3143 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
3145 face
= best
= best_bitmap
= NULL
;
3146 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3148 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3150 new_score
= (face
->Italic
^ it
) + (face
->Bold
^ bd
);
3151 if(!best
|| new_score
<= score
)
3153 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3154 face
->Italic
, face
->Bold
, it
, bd
);
3157 if(best
->scalable
&& score
== 0) break;
3161 newdiff
= height
- (signed int)(best
->size
.height
);
3163 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3164 if(!best_bitmap
|| new_score
< score
||
3165 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3167 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3170 if(score
== 0 && diff
== 0) break;
3177 face
= best
->scalable
? best
: best_bitmap
;
3178 ret
->fake_italic
= (it
&& !face
->Italic
);
3179 ret
->fake_bold
= (bd
&& !face
->Bold
);
3181 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
3183 if(csi
.fs
.fsCsb
[0]) {
3184 ret
->charset
= lf
.lfCharSet
;
3185 ret
->codepage
= csi
.ciACP
;
3188 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3190 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3191 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3193 ret
->aveWidth
= abs(lf
.lfWidth
);
3195 if(!face
->scalable
) {
3196 /* Windows uses integer scaling factors for bitmap fonts */
3197 INT scale
, scaled_height
;
3199 if (height
!= 0) height
= diff
;
3201 height
+= face
->size
.height
;
3203 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3204 scaled_height
= scale
* face
->size
.height
;
3205 /* XP allows not more than 10% deviation */
3206 if (scale
> 1 && scaled_height
- height
> scaled_height
/ 10) scale
--;
3207 ret
->scale_y
= scale
;
3209 width
= face
->size
.x_ppem
>> 6;
3210 height
= face
->size
.y_ppem
>> 6;
3214 TRACE("font scale y: %f\n", ret
->scale_y
);
3216 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3221 LeaveCriticalSection( &freetype_cs
);
3225 ret
->ntmFlags
= face
->ntmFlags
;
3227 if (ret
->charset
== SYMBOL_CHARSET
&&
3228 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3231 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3235 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3238 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3239 ret
->name
= strdupW(family
->FamilyName
);
3240 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3241 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3242 create_child_font_list(ret
);
3244 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3246 list_add_head(&gdi_font_list
, &ret
->entry
);
3247 LeaveCriticalSection( &freetype_cs
);
3251 static void dump_gdi_font_list(void)
3254 struct list
*elem_ptr
;
3256 TRACE("---------- gdiFont Cache ----------\n");
3257 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3258 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3259 TRACE("gdiFont=%p %s %d\n",
3260 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3263 TRACE("---------- Unused gdiFont Cache ----------\n");
3264 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3265 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3266 TRACE("gdiFont=%p %s %d\n",
3267 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3271 /*************************************************************
3272 * WineEngDestroyFontInstance
3274 * free the gdiFont associated with this handle
3277 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3282 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3285 EnterCriticalSection( &freetype_cs
);
3287 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3289 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3290 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3291 if(hflist
->hfont
== handle
)
3293 TRACE("removing child font %p from child list\n", gdiFont
);
3294 list_remove(&gdiFont
->entry
);
3295 LeaveCriticalSection( &freetype_cs
);
3300 TRACE("destroying hfont=%p\n", handle
);
3302 dump_gdi_font_list();
3304 font_elem_ptr
= list_head(&gdi_font_list
);
3305 while(font_elem_ptr
) {
3306 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3307 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3309 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3310 while(hfontlist_elem_ptr
) {
3311 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3312 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3313 if(hflist
->hfont
== handle
) {
3314 list_remove(&hflist
->entry
);
3315 HeapFree(GetProcessHeap(), 0, hflist
);
3319 if(list_empty(&gdiFont
->hfontlist
)) {
3320 TRACE("Moving to Unused list\n");
3321 list_remove(&gdiFont
->entry
);
3322 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3327 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3328 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3329 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3330 while(font_elem_ptr
) {
3331 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3332 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3333 TRACE("freeing %p\n", gdiFont
);
3334 list_remove(&gdiFont
->entry
);
3337 LeaveCriticalSection( &freetype_cs
);
3341 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3342 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3347 if (face
->cached_enum_data
)
3350 memcpy(pelf
, &face
->cached_enum_data
->elf
, sizeof(ENUMLOGFONTEXW
));
3351 memcpy(pntm
, &face
->cached_enum_data
->ntm
, sizeof(NEWTEXTMETRICEXW
));
3352 *ptype
= face
->cached_enum_data
->type
;
3356 font
= alloc_font();
3358 if(face
->scalable
) {
3362 height
= face
->size
.y_ppem
>> 6;
3363 width
= face
->size
.x_ppem
>> 6;
3365 font
->scale_y
= 1.0;
3367 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3373 font
->name
= strdupW(face
->family
->FamilyName
);
3374 font
->ntmFlags
= face
->ntmFlags
;
3376 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3378 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3380 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3382 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3383 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3385 lstrcpynW(pelf
->elfFullName
,
3386 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
3388 lstrcpynW(pelf
->elfStyle
,
3389 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
3394 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
3396 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3398 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3399 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
3400 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
3403 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
3404 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3405 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3406 memcpy(&pntm
->ntmFontSig
, &face
->fs
, sizeof(FONTSIGNATURE
));
3408 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3410 pelf
->elfLogFont
.lfEscapement
= 0;
3411 pelf
->elfLogFont
.lfOrientation
= 0;
3412 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
3413 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3414 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
3415 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
3416 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
3417 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
3418 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
3419 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3420 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3421 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3422 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3425 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
3426 *ptype
|= TRUETYPE_FONTTYPE
;
3427 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
3428 *ptype
|= DEVICE_FONTTYPE
;
3429 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
3430 *ptype
|= RASTER_FONTTYPE
;
3432 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
3433 if (face
->cached_enum_data
)
3435 memcpy(&face
->cached_enum_data
->elf
, pelf
, sizeof(ENUMLOGFONTEXW
));
3436 memcpy(&face
->cached_enum_data
->ntm
, pntm
, sizeof(NEWTEXTMETRICEXW
));
3437 face
->cached_enum_data
->type
= *ptype
;
3443 /*************************************************************
3447 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3451 struct list
*family_elem_ptr
, *face_elem_ptr
;
3453 NEWTEXTMETRICEXW ntm
;
3462 lf
.lfCharSet
= DEFAULT_CHARSET
;
3463 lf
.lfPitchAndFamily
= 0;
3464 lf
.lfFaceName
[0] = 0;
3468 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3470 EnterCriticalSection( &freetype_cs
);
3471 if(plf
->lfFaceName
[0]) {
3473 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3476 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3477 debugstr_w(psub
->to
.name
));
3478 memcpy(&lf
, plf
, sizeof(lf
));
3479 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3483 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3484 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3485 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3486 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3487 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3488 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3489 for(i
= 0; i
< 32; i
++) {
3490 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3491 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3492 strcpyW(elf
.elfScript
, OEM_DOSW
);
3493 i
= 32; /* break out of loop */
3494 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3497 fs
.fsCsb
[0] = 1L << i
;
3499 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3501 csi
.ciCharset
= DEFAULT_CHARSET
;
3502 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3503 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3504 elf
.elfLogFont
.lfCharSet
=
3505 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3507 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3509 FIXME("Unknown elfscript for bit %d\n", i
);
3512 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3513 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3514 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3515 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3516 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3517 ntm
.ntmTm
.ntmFlags
);
3518 /* release section before callback (FIXME) */
3519 LeaveCriticalSection( &freetype_cs
);
3520 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3521 EnterCriticalSection( &freetype_cs
);
3527 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3528 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3529 face_elem_ptr
= list_head(&family
->faces
);
3530 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3531 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3532 for(i
= 0; i
< 32; i
++) {
3533 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3534 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3535 strcpyW(elf
.elfScript
, OEM_DOSW
);
3536 i
= 32; /* break out of loop */
3537 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3540 fs
.fsCsb
[0] = 1L << i
;
3542 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3544 csi
.ciCharset
= DEFAULT_CHARSET
;
3545 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3546 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3547 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3550 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3552 FIXME("Unknown elfscript for bit %d\n", i
);
3555 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3556 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3557 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3558 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3559 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3560 ntm
.ntmTm
.ntmFlags
);
3561 /* release section before callback (FIXME) */
3562 LeaveCriticalSection( &freetype_cs
);
3563 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3564 EnterCriticalSection( &freetype_cs
);
3568 LeaveCriticalSection( &freetype_cs
);
3572 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3574 pt
->x
.value
= vec
->x
>> 6;
3575 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3576 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3577 pt
->y
.value
= vec
->y
>> 6;
3578 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3579 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3583 /***************************************************
3584 * According to the MSDN documentation on WideCharToMultiByte,
3585 * certain codepages cannot set the default_used parameter.
3586 * This returns TRUE if the codepage can set that parameter, false else
3587 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3589 static BOOL
codepage_sets_default_used(UINT codepage
)
3602 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
3604 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
3605 WCHAR wc
= (WCHAR
)glyph
;
3607 BOOL
*default_used_pointer
;
3610 default_used_pointer
= NULL
;
3611 default_used
= FALSE
;
3612 if (codepage_sets_default_used(font
->codepage
))
3613 default_used_pointer
= &default_used
;
3614 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
3617 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
3618 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
3622 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
3623 glyph
= glyph
+ 0xf000;
3624 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
3627 /*************************************************************
3628 * WineEngGetGlyphIndices
3630 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3632 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
3633 LPWORD pgi
, DWORD flags
)
3636 WCHAR default_char
= 0;
3639 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0x001f; /* Indicate non existence */
3641 for(i
= 0; i
< count
; i
++)
3643 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
3648 WineEngGetTextMetrics(font
, &textm
);
3649 default_char
= textm
.tmDefaultChar
;
3651 pgi
[i
] = default_char
;
3657 /*************************************************************
3658 * WineEngGetGlyphOutline
3660 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3661 * except that the first parameter is the HWINEENGFONT of the font in
3662 * question rather than an HDC.
3665 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
3666 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3669 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
3670 FT_Face ft_face
= incoming_font
->ft_face
;
3671 GdiFont
*font
= incoming_font
;
3672 FT_UInt glyph_index
;
3673 DWORD width
, height
, pitch
, needed
= 0;
3674 FT_Bitmap ft_bitmap
;
3676 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
3678 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3679 float widthRatio
= 1.0;
3680 FT_Matrix transMat
= identityMat
;
3681 BOOL needsTransform
= FALSE
;
3684 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
3685 buflen
, buf
, lpmat
);
3687 EnterCriticalSection( &freetype_cs
);
3689 if(format
& GGO_GLYPH_INDEX
) {
3690 glyph_index
= glyph
;
3691 format
&= ~GGO_GLYPH_INDEX
;
3693 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
3694 ft_face
= font
->ft_face
;
3697 if(glyph_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
3698 font
->gmsize
= (glyph_index
/ GM_BLOCK_SIZE
+ 1);
3699 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
3700 font
->gmsize
* sizeof(GM
*));
3702 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] != NULL
&& FONT_GM(font
,glyph_index
)->init
) {
3703 *lpgm
= FONT_GM(font
,glyph_index
)->gm
;
3704 LeaveCriticalSection( &freetype_cs
);
3705 return 1; /* FIXME */
3709 if (!font
->gm
[glyph_index
/ GM_BLOCK_SIZE
])
3710 font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3712 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) || lpmat
)
3713 load_flags
|= FT_LOAD_NO_BITMAP
;
3715 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
3718 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
3719 LeaveCriticalSection( &freetype_cs
);
3723 /* Scaling factor */
3724 if (font
->aveWidth
&& font
->potm
)
3726 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
3727 widthRatio
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
3730 widthRatio
= font
->scale_y
;
3732 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
3733 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
3735 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
3737 bbx
= (right
- left
) >> 6;
3739 /* Scaling transform */
3740 if(font
->aveWidth
) {
3742 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
3745 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
3747 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
3748 needsTransform
= TRUE
;
3751 /* Slant transform */
3752 if (font
->fake_italic
) {
3755 slantMat
.xx
= (1 << 16);
3756 slantMat
.xy
= ((1 << 16) >> 2);
3758 slantMat
.yy
= (1 << 16);
3759 pFT_Matrix_Multiply(&slantMat
, &transMat
);
3760 needsTransform
= TRUE
;
3763 /* Rotation transform */
3764 if(font
->orientation
) {
3765 FT_Matrix rotationMat
;
3767 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
3768 pFT_Vector_Unit(&vecAngle
, angle
);
3769 rotationMat
.xx
= vecAngle
.x
;
3770 rotationMat
.xy
= -vecAngle
.y
;
3771 rotationMat
.yx
= -rotationMat
.xy
;
3772 rotationMat
.yy
= rotationMat
.xx
;
3774 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
3775 needsTransform
= TRUE
;
3778 /* Extra transformation specified by caller */
3781 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
3782 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
3783 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
3784 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
3785 pFT_Matrix_Multiply(&extraMat
, &transMat
);
3786 needsTransform
= TRUE
;
3789 if(!needsTransform
) {
3790 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
3791 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
3792 ft_face
->glyph
->metrics
.height
) & -64;
3793 lpgm
->gmCellIncX
= adv
;
3794 lpgm
->gmCellIncY
= 0;
3798 for(xc
= 0; xc
< 2; xc
++) {
3799 for(yc
= 0; yc
< 2; yc
++) {
3800 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
3801 xc
* ft_face
->glyph
->metrics
.width
);
3802 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
3803 yc
* ft_face
->glyph
->metrics
.height
;
3804 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
3805 pFT_Vector_Transform(&vec
, &transMat
);
3806 if(xc
== 0 && yc
== 0) {
3807 left
= right
= vec
.x
;
3808 top
= bottom
= vec
.y
;
3810 if(vec
.x
< left
) left
= vec
.x
;
3811 else if(vec
.x
> right
) right
= vec
.x
;
3812 if(vec
.y
< bottom
) bottom
= vec
.y
;
3813 else if(vec
.y
> top
) top
= vec
.y
;
3818 right
= (right
+ 63) & -64;
3819 bottom
= bottom
& -64;
3820 top
= (top
+ 63) & -64;
3822 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
3823 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
3825 pFT_Vector_Transform(&vec
, &transMat
);
3826 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
3827 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
3829 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
3830 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
3831 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
3832 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
3834 if(format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
)
3836 FONT_GM(font
,glyph_index
)->gm
= *lpgm
;
3837 FONT_GM(font
,glyph_index
)->adv
= adv
;
3838 FONT_GM(font
,glyph_index
)->lsb
= lsb
;
3839 FONT_GM(font
,glyph_index
)->bbx
= bbx
;
3840 FONT_GM(font
,glyph_index
)->init
= TRUE
;
3843 if(format
== GGO_METRICS
)
3845 LeaveCriticalSection( &freetype_cs
);
3846 return 1; /* FIXME */
3849 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) {
3850 TRACE("loaded a bitmap\n");
3851 LeaveCriticalSection( &freetype_cs
);
3857 width
= lpgm
->gmBlackBoxX
;
3858 height
= lpgm
->gmBlackBoxY
;
3859 pitch
= ((width
+ 31) >> 5) << 2;
3860 needed
= pitch
* height
;
3862 if(!buf
|| !buflen
) break;
3864 switch(ft_face
->glyph
->format
) {
3865 case ft_glyph_format_bitmap
:
3867 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3868 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
3869 INT h
= ft_face
->glyph
->bitmap
.rows
;
3871 memcpy(dst
, src
, w
);
3872 src
+= ft_face
->glyph
->bitmap
.pitch
;
3878 case ft_glyph_format_outline
:
3879 ft_bitmap
.width
= width
;
3880 ft_bitmap
.rows
= height
;
3881 ft_bitmap
.pitch
= pitch
;
3882 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
3883 ft_bitmap
.buffer
= buf
;
3885 if(needsTransform
) {
3886 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3889 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3891 /* Note: FreeType will only set 'black' bits for us. */
3892 memset(buf
, 0, needed
);
3893 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3897 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3898 LeaveCriticalSection( &freetype_cs
);
3903 case GGO_GRAY2_BITMAP
:
3904 case GGO_GRAY4_BITMAP
:
3905 case GGO_GRAY8_BITMAP
:
3906 case WINE_GGO_GRAY16_BITMAP
:
3908 unsigned int mult
, row
, col
;
3911 width
= lpgm
->gmBlackBoxX
;
3912 height
= lpgm
->gmBlackBoxY
;
3913 pitch
= (width
+ 3) / 4 * 4;
3914 needed
= pitch
* height
;
3916 if(!buf
|| !buflen
) break;
3918 switch(ft_face
->glyph
->format
) {
3919 case ft_glyph_format_bitmap
:
3921 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3922 INT h
= ft_face
->glyph
->bitmap
.rows
;
3925 for(x
= 0; x
< pitch
; x
++)
3926 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
3927 src
+= ft_face
->glyph
->bitmap
.pitch
;
3930 LeaveCriticalSection( &freetype_cs
);
3933 case ft_glyph_format_outline
:
3935 ft_bitmap
.width
= width
;
3936 ft_bitmap
.rows
= height
;
3937 ft_bitmap
.pitch
= pitch
;
3938 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
3939 ft_bitmap
.buffer
= buf
;
3942 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3944 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3946 memset(ft_bitmap
.buffer
, 0, buflen
);
3948 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3950 if(format
== GGO_GRAY2_BITMAP
)
3952 else if(format
== GGO_GRAY4_BITMAP
)
3954 else if(format
== GGO_GRAY8_BITMAP
)
3956 else /* format == WINE_GGO_GRAY16_BITMAP */
3958 LeaveCriticalSection( &freetype_cs
);
3964 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3965 LeaveCriticalSection( &freetype_cs
);
3970 for(row
= 0; row
< height
; row
++) {
3972 for(col
= 0; col
< width
; col
++, ptr
++) {
3973 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
3982 int contour
, point
= 0, first_pt
;
3983 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3984 TTPOLYGONHEADER
*pph
;
3986 DWORD pph_start
, cpfx
, type
;
3988 if(buflen
== 0) buf
= NULL
;
3990 if (needsTransform
&& buf
) {
3991 pFT_Outline_Transform(outline
, &transMat
);
3994 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3996 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3999 pph
->dwType
= TT_POLYGON_TYPE
;
4000 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4002 needed
+= sizeof(*pph
);
4004 while(point
<= outline
->contours
[contour
]) {
4005 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4006 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4007 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
4011 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4014 } while(point
<= outline
->contours
[contour
] &&
4015 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4016 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4017 /* At the end of a contour Windows adds the start point, but
4019 if(point
> outline
->contours
[contour
] &&
4020 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4022 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
4024 } else if(point
<= outline
->contours
[contour
] &&
4025 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4026 /* add closing pt for bezier */
4028 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4036 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4039 pph
->cb
= needed
- pph_start
;
4045 /* Convert the quadratic Beziers to cubic Beziers.
4046 The parametric eqn for a cubic Bezier is, from PLRM:
4047 r(t) = at^3 + bt^2 + ct + r0
4048 with the control points:
4053 A quadratic Beizer has the form:
4054 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4056 So equating powers of t leads to:
4057 r1 = 2/3 p1 + 1/3 p0
4058 r2 = 2/3 p1 + 1/3 p2
4059 and of course r0 = p0, r3 = p2
4062 int contour
, point
= 0, first_pt
;
4063 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4064 TTPOLYGONHEADER
*pph
;
4066 DWORD pph_start
, cpfx
, type
;
4067 FT_Vector cubic_control
[4];
4068 if(buflen
== 0) buf
= NULL
;
4070 if (needsTransform
&& buf
) {
4071 pFT_Outline_Transform(outline
, &transMat
);
4074 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4076 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4079 pph
->dwType
= TT_POLYGON_TYPE
;
4080 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4082 needed
+= sizeof(*pph
);
4084 while(point
<= outline
->contours
[contour
]) {
4085 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4086 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4087 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
4090 if(type
== TT_PRIM_LINE
) {
4092 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4096 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4099 /* FIXME: Possible optimization in endpoint calculation
4100 if there are two consecutive curves */
4101 cubic_control
[0] = outline
->points
[point
-1];
4102 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4103 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
4104 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
4105 cubic_control
[0].x
>>= 1;
4106 cubic_control
[0].y
>>= 1;
4108 if(point
+1 > outline
->contours
[contour
])
4109 cubic_control
[3] = outline
->points
[first_pt
];
4111 cubic_control
[3] = outline
->points
[point
+1];
4112 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
4113 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
4114 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
4115 cubic_control
[3].x
>>= 1;
4116 cubic_control
[3].y
>>= 1;
4119 /* r1 = 1/3 p0 + 2/3 p1
4120 r2 = 1/3 p2 + 2/3 p1 */
4121 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
4122 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
4123 cubic_control
[2] = cubic_control
[1];
4124 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
4125 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
4126 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
4127 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
4129 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
4130 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
4131 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
4136 } while(point
<= outline
->contours
[contour
] &&
4137 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4138 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4139 /* At the end of a contour Windows adds the start point,
4140 but only for Beziers and we've already done that.
4142 if(point
<= outline
->contours
[contour
] &&
4143 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4144 /* This is the closing pt of a bezier, but we've already
4145 added it, so just inc point and carry on */
4152 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4155 pph
->cb
= needed
- pph_start
;
4161 FIXME("Unsupported format %d\n", format
);
4162 LeaveCriticalSection( &freetype_cs
);
4165 LeaveCriticalSection( &freetype_cs
);
4169 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
4171 FT_Face ft_face
= font
->ft_face
;
4172 #ifdef HAVE_FREETYPE_FTWINFNT_H
4173 FT_WinFNT_HeaderRec winfnt_header
;
4175 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
4176 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
4177 font
->potm
->otmSize
= size
;
4179 #define TM font->potm->otmTextMetrics
4180 #ifdef HAVE_FREETYPE_FTWINFNT_H
4181 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
4183 TM
.tmHeight
= winfnt_header
.pixel_height
;
4184 TM
.tmAscent
= winfnt_header
.ascent
;
4185 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
4186 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
4187 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
4188 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
4189 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4190 TM
.tmWeight
= winfnt_header
.weight
;
4192 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4193 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4194 TM
.tmFirstChar
= winfnt_header
.first_char
;
4195 TM
.tmLastChar
= winfnt_header
.last_char
;
4196 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4197 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4198 TM
.tmItalic
= winfnt_header
.italic
;
4199 TM
.tmUnderlined
= font
->underline
;
4200 TM
.tmStruckOut
= font
->strikeout
;
4201 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4202 TM
.tmCharSet
= winfnt_header
.charset
;
4207 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4208 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4209 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4210 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4211 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4212 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4213 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4214 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4216 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4217 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4219 TM
.tmLastChar
= 255;
4220 TM
.tmDefaultChar
= 32;
4221 TM
.tmBreakChar
= 32;
4222 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4223 TM
.tmUnderlined
= font
->underline
;
4224 TM
.tmStruckOut
= font
->strikeout
;
4225 /* NB inverted meaning of TMPF_FIXED_PITCH */
4226 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4227 TM
.tmCharSet
= font
->charset
;
4235 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
4241 scale_x
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4242 scale_x
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4245 scale_x
= font
->scale_y
;
4247 ptm
->tmHeight
= (float)ptm
->tmHeight
* font
->scale_y
;
4248 ptm
->tmAscent
= (float)ptm
->tmAscent
* font
->scale_y
;
4249 ptm
->tmDescent
= (float)ptm
->tmDescent
* font
->scale_y
;
4250 ptm
->tmInternalLeading
= (float)ptm
->tmInternalLeading
* font
->scale_y
;
4251 ptm
->tmExternalLeading
= (float)ptm
->tmExternalLeading
* font
->scale_y
;
4253 ptm
->tmAveCharWidth
= (float)ptm
->tmAveCharWidth
* scale_x
;
4254 ptm
->tmMaxCharWidth
= (float)ptm
->tmMaxCharWidth
* scale_x
;
4257 /*************************************************************
4258 * WineEngGetTextMetrics
4261 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4263 EnterCriticalSection( &freetype_cs
);
4265 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4266 if(!get_bitmap_text_metrics(font
))
4268 LeaveCriticalSection( &freetype_cs
);
4274 LeaveCriticalSection( &freetype_cs
);
4277 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
4278 scale_font_metrics(font
, ptm
);
4279 LeaveCriticalSection( &freetype_cs
);
4284 /*************************************************************
4285 * WineEngGetOutlineTextMetrics
4288 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4289 OUTLINETEXTMETRICW
*potm
)
4291 FT_Face ft_face
= font
->ft_face
;
4292 UINT needed
, lenfam
, lensty
, ret
;
4294 TT_HoriHeader
*pHori
;
4295 TT_Postscript
*pPost
;
4296 FT_Fixed x_scale
, y_scale
;
4297 WCHAR
*family_nameW
, *style_nameW
;
4298 static const WCHAR spaceW
[] = {' ', '\0'};
4300 INT ascent
, descent
;
4302 TRACE("font=%p\n", font
);
4304 if(!FT_IS_SCALABLE(ft_face
))
4307 EnterCriticalSection( &freetype_cs
);
4310 if(cbSize
>= font
->potm
->otmSize
)
4312 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4313 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4315 LeaveCriticalSection( &freetype_cs
);
4316 return font
->potm
->otmSize
;
4320 needed
= sizeof(*potm
);
4322 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
4323 family_nameW
= strdupW(font
->name
);
4325 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
4327 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
4328 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
4329 style_nameW
, lensty
/sizeof(WCHAR
));
4331 /* These names should be read from the TT name table */
4333 /* length of otmpFamilyName */
4336 /* length of otmpFaceName */
4337 if(!strcasecmp(ft_face
->style_name
, "regular")) {
4338 needed
+= lenfam
; /* just the family name */
4340 needed
+= lenfam
+ lensty
; /* family + " " + style */
4343 /* length of otmpStyleName */
4346 /* length of otmpFullName */
4347 needed
+= lenfam
+ lensty
;
4350 x_scale
= ft_face
->size
->metrics
.x_scale
;
4351 y_scale
= ft_face
->size
->metrics
.y_scale
;
4353 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4355 FIXME("Can't find OS/2 table - not TT font?\n");
4360 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4362 FIXME("Can't find HHEA table - not TT font?\n");
4367 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
4369 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",
4370 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
4371 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
4372 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
4373 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
4374 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
4376 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
4377 font
->potm
->otmSize
= needed
;
4379 #define TM font->potm->otmTextMetrics
4381 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
4382 ascent
= pHori
->Ascender
;
4383 descent
= -pHori
->Descender
;
4385 ascent
= pOS2
->usWinAscent
;
4386 descent
= pOS2
->usWinDescent
;
4390 TM
.tmAscent
= font
->yMax
;
4391 TM
.tmDescent
= -font
->yMin
;
4392 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4394 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4395 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4396 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4397 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4400 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4403 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4405 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4406 ((ascent
+ descent
) -
4407 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4409 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4410 if (TM
.tmAveCharWidth
== 0) {
4411 TM
.tmAveCharWidth
= 1;
4413 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4414 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4416 TM
.tmDigitizedAspectX
= 300;
4417 TM
.tmDigitizedAspectY
= 300;
4418 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4419 * symbol range to 0 - f0ff
4421 if (font
->charset
== SYMBOL_CHARSET
)
4424 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4425 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4426 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4427 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4428 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4429 TM
.tmUnderlined
= font
->underline
;
4430 TM
.tmStruckOut
= font
->strikeout
;
4432 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4433 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4434 (pOS2
->version
== 0xFFFFU
||
4435 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4436 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4438 TM
.tmPitchAndFamily
= 0;
4440 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4441 case PAN_FAMILY_SCRIPT
:
4442 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4444 case PAN_FAMILY_DECORATIVE
:
4445 case PAN_FAMILY_PICTORIAL
:
4446 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4448 case PAN_FAMILY_TEXT_DISPLAY
:
4449 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4450 TM
.tmPitchAndFamily
= FF_MODERN
;
4452 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4453 case PAN_SERIF_NORMAL_SANS
:
4454 case PAN_SERIF_OBTUSE_SANS
:
4455 case PAN_SERIF_PERP_SANS
:
4456 TM
.tmPitchAndFamily
|= FF_SWISS
;
4459 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4464 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4467 if(FT_IS_SCALABLE(ft_face
))
4468 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4470 if(FT_IS_SFNT(ft_face
))
4472 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
4473 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
4475 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4478 TM
.tmCharSet
= font
->charset
;
4481 font
->potm
->otmFiller
= 0;
4482 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4483 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4484 font
->potm
->otmfsType
= pOS2
->fsType
;
4485 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4486 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4487 font
->potm
->otmItalicAngle
= 0; /* POST table */
4488 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4489 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4490 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4491 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4492 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4493 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
4494 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4495 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
4496 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
4497 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
4498 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
4499 font
->potm
->otmMacDescent
= 0;
4500 font
->potm
->otmMacLineGap
= 0;
4501 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
4502 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
4503 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
4504 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
4505 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
4506 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
4507 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
4508 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
4509 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
4510 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
4511 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
4513 font
->potm
->otmsUnderscoreSize
= 0;
4514 font
->potm
->otmsUnderscorePosition
= 0;
4516 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
4517 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
4520 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4521 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
4522 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
4523 strcpyW((WCHAR
*)cp
, family_nameW
);
4525 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
4526 strcpyW((WCHAR
*)cp
, style_nameW
);
4528 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
4529 strcpyW((WCHAR
*)cp
, family_nameW
);
4530 if(strcasecmp(ft_face
->style_name
, "regular")) {
4531 strcatW((WCHAR
*)cp
, spaceW
);
4532 strcatW((WCHAR
*)cp
, style_nameW
);
4533 cp
+= lenfam
+ lensty
;
4536 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
4537 strcpyW((WCHAR
*)cp
, family_nameW
);
4538 strcatW((WCHAR
*)cp
, spaceW
);
4539 strcatW((WCHAR
*)cp
, style_nameW
);
4542 if(potm
&& needed
<= cbSize
)
4544 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4545 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4549 HeapFree(GetProcessHeap(), 0, style_nameW
);
4550 HeapFree(GetProcessHeap(), 0, family_nameW
);
4552 LeaveCriticalSection( &freetype_cs
);
4556 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
4558 HFONTLIST
*hfontlist
;
4559 child
->font
= alloc_font();
4560 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
4561 if(!child
->font
->ft_face
)
4563 free_font(child
->font
);
4568 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
4569 child
->font
->orientation
= font
->orientation
;
4570 child
->font
->scale_y
= font
->scale_y
;
4571 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
4572 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
4573 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
4574 child
->font
->base_font
= font
;
4575 list_add_head(&child_font_list
, &child
->font
->entry
);
4576 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
4580 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
4583 CHILD_FONT
*child_font
;
4586 font
= font
->base_font
;
4588 *linked_font
= font
;
4590 if((*glyph
= get_glyph_index(font
, c
)))
4593 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
4595 if(!child_font
->font
)
4596 if(!load_child_font(font
, child_font
))
4599 if(!child_font
->font
->ft_face
)
4601 g
= get_glyph_index(child_font
->font
, c
);
4605 *linked_font
= child_font
->font
;
4612 /*************************************************************
4613 * WineEngGetCharWidth
4616 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4621 FT_UInt glyph_index
;
4622 GdiFont
*linked_font
;
4624 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4626 EnterCriticalSection( &freetype_cs
);
4627 for(c
= firstChar
; c
<= lastChar
; c
++) {
4628 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4629 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4630 &gm
, 0, NULL
, NULL
);
4631 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
4633 LeaveCriticalSection( &freetype_cs
);
4637 /*************************************************************
4638 * WineEngGetCharABCWidths
4641 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4646 FT_UInt glyph_index
;
4647 GdiFont
*linked_font
;
4649 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4651 if(!FT_IS_SCALABLE(font
->ft_face
))
4654 EnterCriticalSection( &freetype_cs
);
4656 for(c
= firstChar
; c
<= lastChar
; c
++) {
4657 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4658 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4659 &gm
, 0, NULL
, NULL
);
4660 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
4661 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
4662 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
4663 FONT_GM(linked_font
,glyph_index
)->bbx
;
4665 LeaveCriticalSection( &freetype_cs
);
4669 /*************************************************************
4670 * WineEngGetCharABCWidthsI
4673 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4678 FT_UInt glyph_index
;
4679 GdiFont
*linked_font
;
4681 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
4684 EnterCriticalSection( &freetype_cs
);
4686 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
4688 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
4689 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4690 &gm
, 0, NULL
, NULL
);
4691 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
4692 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
4693 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
4694 - FONT_GM(linked_font
,c
)->bbx
;
4697 for(c
= 0; c
< count
; c
++) {
4698 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4699 &gm
, 0, NULL
, NULL
);
4700 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
4701 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
4702 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
4703 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
4706 LeaveCriticalSection( &freetype_cs
);
4710 /*************************************************************
4711 * WineEngGetTextExtentExPoint
4714 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4715 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4721 FT_UInt glyph_index
;
4722 GdiFont
*linked_font
;
4724 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
4727 EnterCriticalSection( &freetype_cs
);
4730 WineEngGetTextMetrics(font
, &tm
);
4731 size
->cy
= tm
.tmHeight
;
4733 for(idx
= 0; idx
< count
; idx
++) {
4734 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
4735 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4736 &gm
, 0, NULL
, NULL
);
4737 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
4739 if (! pnfit
|| ext
<= max_ext
) {
4749 LeaveCriticalSection( &freetype_cs
);
4750 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4754 /*************************************************************
4755 * WineEngGetTextExtentExPointI
4758 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4759 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4766 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
4768 EnterCriticalSection( &freetype_cs
);
4771 WineEngGetTextMetrics(font
, &tm
);
4772 size
->cy
= tm
.tmHeight
;
4774 for(idx
= 0; idx
< count
; idx
++) {
4775 WineEngGetGlyphOutline(font
, indices
[idx
],
4776 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
4778 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
4780 if (! pnfit
|| ext
<= max_ext
) {
4790 LeaveCriticalSection( &freetype_cs
);
4791 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4795 /*************************************************************
4796 * WineEngGetFontData
4799 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4802 FT_Face ft_face
= font
->ft_face
;
4806 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4807 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
4808 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
4810 if(!FT_IS_SFNT(ft_face
))
4818 if(table
) { /* MS tags differ in endidness from FT ones */
4819 table
= table
>> 24 | table
<< 24 |
4820 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
4823 /* make sure value of len is the value freetype says it needs */
4826 FT_ULong needed
= 0;
4827 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
4828 if( !err
&& needed
< len
) len
= needed
;
4830 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
4833 TRACE("Can't find table %c%c%c%c\n",
4834 /* bytes were reversed */
4835 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4836 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4842 /*************************************************************
4843 * WineEngGetTextFace
4846 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4849 lstrcpynW(str
, font
->name
, count
);
4850 return strlenW(font
->name
);
4852 return strlenW(font
->name
) + 1;
4855 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4857 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
4858 return font
->charset
;
4861 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4863 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
4864 struct list
*first_hfont
;
4867 EnterCriticalSection( &freetype_cs
);
4868 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
4869 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
4870 if(font
== linked_font
)
4871 *new_hfont
= dc
->hFont
;
4874 first_hfont
= list_head(&linked_font
->hfontlist
);
4875 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
4877 LeaveCriticalSection( &freetype_cs
);
4881 /* Retrieve a list of supported Unicode ranges for a given font.
4882 * Can be called with NULL gs to calculate the buffer size. Returns
4883 * the number of ranges found.
4885 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
4887 DWORD num_ranges
= 0;
4889 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4892 FT_ULong char_code
, char_code_prev
;
4895 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
4897 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4898 face
->num_glyphs
, glyph_code
, char_code
);
4900 if (!glyph_code
) return 0;
4904 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4905 gs
->ranges
[0].cGlyphs
= 0;
4906 gs
->cGlyphsSupported
= 0;
4912 if (char_code
< char_code_prev
)
4914 ERR("expected increasing char code from FT_Get_Next_Char\n");
4917 if (char_code
- char_code_prev
> 1)
4922 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4923 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4924 gs
->cGlyphsSupported
++;
4929 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4930 gs
->cGlyphsSupported
++;
4932 char_code_prev
= char_code
;
4933 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
4937 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
4942 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
4945 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
4947 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
4950 glyphset
->cbThis
= size
;
4951 glyphset
->cRanges
= num_ranges
;
4956 /*************************************************************
4959 BOOL
WineEngFontIsLinked(GdiFont
*font
)
4962 EnterCriticalSection( &freetype_cs
);
4963 ret
= !list_empty(&font
->child_fonts
);
4964 LeaveCriticalSection( &freetype_cs
);
4968 static BOOL
is_hinting_enabled(void)
4970 /* Use the >= 2.2.0 function if available */
4971 if(pFT_Get_TrueType_Engine_Type
)
4973 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
4974 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
4976 #ifdef FT_DRIVER_HAS_HINTER
4981 /* otherwise if we've been compiled with < 2.2.0 headers
4982 use the internal macro */
4983 mod
= pFT_Get_Module(library
, "truetype");
4984 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
4992 /*************************************************************************
4993 * GetRasterizerCaps (GDI32.@)
4995 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
4997 static int hinting
= -1;
5001 hinting
= is_hinting_enabled();
5002 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
5005 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5006 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
5007 lprs
->nLanguageID
= 0;
5011 /*************************************************************************
5012 * Kerning support for TrueType fonts
5014 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5016 struct TT_kern_table
5022 struct TT_kern_subtable
5031 USHORT horizontal
: 1;
5033 USHORT cross_stream
: 1;
5034 USHORT override
: 1;
5035 USHORT reserved1
: 4;
5041 struct TT_format0_kern_subtable
5045 USHORT entrySelector
;
5056 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
5057 const struct TT_format0_kern_subtable
*tt_f0_ks
,
5058 const USHORT
*glyph_to_char
,
5059 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
5062 const struct TT_kern_pair
*tt_kern_pair
;
5064 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
5066 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
5068 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5069 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
5070 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
5072 if (!kern_pair
|| !cPairs
)
5075 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
5077 nPairs
= min(nPairs
, cPairs
);
5079 for (i
= 0; i
< nPairs
; i
++)
5081 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
5082 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
5083 /* this algorithm appears to better match what Windows does */
5084 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
5085 if (kern_pair
->iKernAmount
< 0)
5087 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
5088 kern_pair
->iKernAmount
-= font
->ppem
;
5090 else if (kern_pair
->iKernAmount
> 0)
5092 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
5093 kern_pair
->iKernAmount
+= font
->ppem
;
5095 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
5097 TRACE("left %u right %u value %d\n",
5098 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
5102 TRACE("copied %u entries\n", nPairs
);
5106 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5110 const struct TT_kern_table
*tt_kern_table
;
5111 const struct TT_kern_subtable
*tt_kern_subtable
;
5113 USHORT
*glyph_to_char
;
5115 EnterCriticalSection( &freetype_cs
);
5116 if (font
->total_kern_pairs
!= (DWORD
)-1)
5118 if (cPairs
&& kern_pair
)
5120 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5121 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5122 LeaveCriticalSection( &freetype_cs
);
5125 LeaveCriticalSection( &freetype_cs
);
5126 return font
->total_kern_pairs
;
5129 font
->total_kern_pairs
= 0;
5131 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
5133 if (length
== GDI_ERROR
)
5135 TRACE("no kerning data in the font\n");
5136 LeaveCriticalSection( &freetype_cs
);
5140 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
5143 WARN("Out of memory\n");
5144 LeaveCriticalSection( &freetype_cs
);
5148 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
5150 /* build a glyph index to char code map */
5151 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
5154 WARN("Out of memory allocating a glyph index to char code map\n");
5155 HeapFree(GetProcessHeap(), 0, buf
);
5156 LeaveCriticalSection( &freetype_cs
);
5160 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5166 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
5168 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5169 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
5173 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5175 /* FIXME: This doesn't match what Windows does: it does some fancy
5176 * things with duplicate glyph index to char code mappings, while
5177 * we just avoid overriding existing entries.
5179 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
5180 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
5182 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
5189 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
5190 for (n
= 0; n
<= 65535; n
++)
5191 glyph_to_char
[n
] = (USHORT
)n
;
5194 tt_kern_table
= buf
;
5195 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
5196 TRACE("version %u, nTables %u\n",
5197 GET_BE_WORD(tt_kern_table
->version
), nTables
);
5199 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
5201 for (i
= 0; i
< nTables
; i
++)
5203 struct TT_kern_subtable tt_kern_subtable_copy
;
5205 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
5206 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
5207 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
5209 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5210 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
5211 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
5213 /* According to the TrueType specification this is the only format
5214 * that will be properly interpreted by Windows and OS/2
5216 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
5218 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
5220 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5221 glyph_to_char
, NULL
, 0);
5222 font
->total_kern_pairs
+= new_chunk
;
5224 if (!font
->kern_pairs
)
5225 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
5226 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5228 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
5229 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5231 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5232 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
5235 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
5237 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
5240 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
5241 HeapFree(GetProcessHeap(), 0, buf
);
5243 if (cPairs
&& kern_pair
)
5245 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5246 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5247 LeaveCriticalSection( &freetype_cs
);
5250 LeaveCriticalSection( &freetype_cs
);
5251 return font
->total_kern_pairs
;
5254 #else /* HAVE_FREETYPE */
5256 /*************************************************************************/
5258 BOOL
WineEngInit(void)
5262 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
5266 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
5271 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5276 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
5277 LPWORD pgi
, DWORD flags
)
5282 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
5283 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5286 ERR("called but we don't have FreeType\n");
5290 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5292 ERR("called but we don't have FreeType\n");
5296 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5297 OUTLINETEXTMETRICW
*potm
)
5299 ERR("called but we don't have FreeType\n");
5303 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5306 ERR("called but we don't have FreeType\n");
5310 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5313 ERR("called but we don't have FreeType\n");
5317 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5320 ERR("called but we don't have FreeType\n");
5324 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5325 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5327 ERR("called but we don't have FreeType\n");
5331 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5332 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5334 ERR("called but we don't have FreeType\n");
5338 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5341 ERR("called but we don't have FreeType\n");
5345 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5347 ERR("called but we don't have FreeType\n");
5351 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5357 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5363 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
5369 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5372 return DEFAULT_CHARSET
;
5375 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5380 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5382 FIXME("(%p, %p): stub\n", font
, glyphset
);
5386 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5391 /*************************************************************************
5392 * GetRasterizerCaps (GDI32.@)
5394 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5396 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5398 lprs
->nLanguageID
= 0;
5402 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5404 ERR("called but we don't have FreeType\n");
5408 #endif /* HAVE_FREETYPE */