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_FTSNAMES_H
106 #include <freetype/ftsnames.h>
108 # ifdef HAVE_FREETYPE_FTNAMES_H
109 # include <freetype/ftnames.h>
112 #ifdef HAVE_FREETYPE_TTNAMEID_H
113 #include <freetype/ttnameid.h>
115 #ifdef HAVE_FREETYPE_FTOUTLN_H
116 #include <freetype/ftoutln.h>
118 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
119 #include <freetype/internal/sfnt.h>
121 #ifdef HAVE_FREETYPE_FTTRIGON_H
122 #include <freetype/fttrigon.h>
124 #ifdef HAVE_FREETYPE_FTWINFNT_H
125 #include <freetype/ftwinfnt.h>
127 #ifdef HAVE_FREETYPE_FTMODAPI_H
128 #include <freetype/ftmodapi.h>
131 #ifndef SONAME_LIBFREETYPE
132 #define SONAME_LIBFREETYPE "libfreetype.so"
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType
;
144 static FT_Library library
= 0;
151 static FT_Version_t FT_Version
;
152 static DWORD FT_SimpleVersion
;
154 static void *ft_handle
= NULL
;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Vector_Unit
);
158 MAKE_FUNCPTR(FT_Done_Face
);
159 MAKE_FUNCPTR(FT_Get_Char_Index
);
160 MAKE_FUNCPTR(FT_Get_Module
);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
164 MAKE_FUNCPTR(FT_Init_FreeType
);
165 MAKE_FUNCPTR(FT_Load_Glyph
);
166 MAKE_FUNCPTR(FT_Matrix_Multiply
);
167 MAKE_FUNCPTR(FT_MulFix
);
168 MAKE_FUNCPTR(FT_New_Face
);
169 MAKE_FUNCPTR(FT_New_Memory_Face
);
170 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
171 MAKE_FUNCPTR(FT_Outline_Transform
);
172 MAKE_FUNCPTR(FT_Outline_Translate
);
173 MAKE_FUNCPTR(FT_Select_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 HAVE_FONTCONFIG_FONTCONFIG_H
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
);
198 #ifndef SONAME_LIBFONTCONFIG
199 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
205 #ifndef ft_encoding_none
206 #define FT_ENCODING_NONE ft_encoding_none
208 #ifndef ft_encoding_ms_symbol
209 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
211 #ifndef ft_encoding_unicode
212 #define FT_ENCODING_UNICODE ft_encoding_unicode
214 #ifndef ft_encoding_apple_roman
215 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
218 #ifdef WORDS_BIGENDIAN
219 #define GET_BE_WORD(x) (x)
221 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
224 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
231 FT_Short internal_leading
;
234 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
235 So to let this compile on older versions of FreeType we'll define the
236 new structure here. */
238 FT_Short height
, width
;
239 FT_Pos size
, x_ppem
, y_ppem
;
242 typedef struct tagFace
{
250 FONTSIGNATURE fs_links
;
251 FT_Fixed font_version
;
253 Bitmap_Size size
; /* set if face is a bitmap */
254 BOOL external
; /* TRUE if we should manually add this font to the registry */
255 struct tagFamily
*family
;
258 typedef struct tagFamily
{
260 const WCHAR
*FamilyName
;
266 INT adv
; /* These three hold to widths of the unrotated chars */
284 typedef struct tagHFONTLIST
{
299 struct font_mapping
*mapping
;
310 struct list hfontlist
;
315 OUTLINETEXTMETRICW
*potm
;
316 DWORD total_kern_pairs
;
317 KERNINGPAIR
*kern_pairs
;
320 struct list child_fonts
;
326 const WCHAR
*font_name
;
330 #define INIT_GM_SIZE 128
332 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
333 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
334 #define UNUSED_CACHE_SIZE 10
335 static struct list child_font_list
= LIST_INIT(child_font_list
);
336 static struct list system_links
= LIST_INIT(system_links
);
338 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
340 static struct list font_list
= LIST_INIT(font_list
);
342 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
343 static const WCHAR defSans
[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
344 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
346 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
348 static const WCHAR fontsW
[] = {'\\','F','o','n','t','s','\0'};
349 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
350 'W','i','n','d','o','w','s','\\',
351 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
352 'F','o','n','t','s','\0'};
354 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
355 'W','i','n','d','o','w','s',' ','N','T','\\',
356 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
357 'F','o','n','t','s','\0'};
359 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
360 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
361 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
362 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
364 static const WCHAR
* const SystemFontValues
[4] = {
371 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
372 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
374 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
375 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
376 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
377 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
378 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
379 'E','u','r','o','p','e','a','n','\0'};
380 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
381 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
382 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
383 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
384 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
385 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
386 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
387 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
388 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
389 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
390 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
391 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
393 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
403 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
411 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
420 typedef struct tagFontSubst
{
436 static struct list mappings_list
= LIST_INIT( mappings_list
);
438 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
440 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
442 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
444 /****************************************
445 * Notes on .fon files
447 * The fonts System, FixedSys and Terminal are special. There are typically multiple
448 * versions installed for different resolutions and codepages. Windows stores which one to use
449 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
451 * FIXEDFON.FON FixedSys
453 * OEMFONT.FON Terminal
454 * LogPixels Current dpi set by the display control panel applet
455 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
456 * also has a LogPixels value that appears to mirror this)
458 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
459 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
460 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
461 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
462 * so that makes sense.
464 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
465 * to be mapped into the registry on Windows 2000 at least).
468 * ega80woa.fon=ega80850.fon
469 * ega40woa.fon=ega40850.fon
470 * cga80woa.fon=cga80850.fon
471 * cga40woa.fon=cga40850.fon
474 #ifdef HAVE_CARBON_CARBON_H
475 static char *find_cache_dir(void)
479 static char cached_path
[MAX_PATH
];
480 static const char *wine
= "/Wine", *fonts
= "/Fonts";
482 if(*cached_path
) return cached_path
;
484 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
487 WARN("can't create cached data folder\n");
490 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
493 WARN("can't create cached data path\n");
497 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
499 ERR("Could not create full path\n");
503 strcat(cached_path
, wine
);
505 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
507 WARN("Couldn't mkdir %s\n", cached_path
);
511 strcat(cached_path
, fonts
);
512 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
514 WARN("Couldn't mkdir %s\n", cached_path
);
521 /******************************************************************
524 * Extracts individual TrueType font files from a Mac suitcase font
525 * and saves them into the user's caches directory (see
527 * Returns a NULL terminated array of filenames.
529 * We do this because they are apps that try to read ttf files
530 * themselves and they don't like Mac suitcase files.
532 static char **expand_mac_font(const char *path
)
539 const char *filename
;
543 unsigned int size
, max_size
;
546 TRACE("path %s\n", path
);
548 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
551 WARN("failed to get ref\n");
555 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
558 TRACE("no data fork, so trying resource fork\n");
559 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
562 TRACE("unable to open resource fork\n");
569 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
572 CloseResFile(res_ref
);
576 out_dir
= find_cache_dir();
578 filename
= strrchr(path
, '/');
579 if(!filename
) filename
= path
;
582 /* output filename has the form out_dir/filename_%04x.ttf */
583 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
590 unsigned short *num_faces_ptr
, num_faces
, face
;
594 fond
= Get1IndResource('FOND', idx
);
596 TRACE("got fond resource %d\n", idx
);
599 fam_rec
= *(FamRec
**)fond
;
600 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
601 num_faces
= GET_BE_WORD(*num_faces_ptr
);
603 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
604 TRACE("num faces %04x\n", num_faces
);
605 for(face
= 0; face
< num_faces
; face
++, assoc
++)
608 unsigned short size
, font_id
;
611 size
= GET_BE_WORD(assoc
->fontSize
);
612 font_id
= GET_BE_WORD(assoc
->fontID
);
615 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
619 TRACE("trying to load sfnt id %04x\n", font_id
);
620 sfnt
= GetResource('sfnt', font_id
);
623 TRACE("can't get sfnt resource %04x\n", font_id
);
627 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
632 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
634 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
635 if(fd
!= -1 || errno
== EEXIST
)
639 unsigned char *sfnt_data
;
642 sfnt_data
= *(unsigned char**)sfnt
;
643 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
647 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
650 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
652 ret
.array
[ret
.size
++] = output
;
656 WARN("unable to create %s\n", output
);
657 HeapFree(GetProcessHeap(), 0, output
);
660 ReleaseResource(sfnt
);
663 ReleaseResource(fond
);
666 CloseResFile(res_ref
);
671 #endif /* HAVE_CARBON_CARBON_H */
673 static inline BOOL
is_win9x(void)
675 return GetVersion() & 0x80000000;
678 This function builds an FT_Fixed from a float. It puts the integer part
679 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
680 It fails if the integer part of the float number is greater than SHORT_MAX.
682 static inline FT_Fixed
FT_FixedFromFloat(float f
)
685 unsigned short fract
= (f
- value
) * 0xFFFF;
686 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
690 This function builds an FT_Fixed from a FIXED. It simply put f.value
691 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
693 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
695 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
699 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
704 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
705 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
707 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
708 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
710 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
712 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
714 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
716 file
= strrchr(face
->file
, '/');
721 if(!strcasecmp(file
, file_nameA
))
723 HeapFree(GetProcessHeap(), 0, file_nameA
);
728 HeapFree(GetProcessHeap(), 0, file_nameA
);
732 static Family
*find_family_from_name(const WCHAR
*name
)
736 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
738 if(!strcmpiW(family
->FamilyName
, name
))
745 static Face
*find_face_from_path_index(const CHAR
*file_name
, const INT index
)
750 TRACE("looking for file %s index %i\n", debugstr_a(file_name
), index
);
752 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
754 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
756 if(!strcasecmp(face
->file
, file_name
) && face
->face_index
== index
)
763 static void DumpSubstList(void)
767 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
769 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
770 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
771 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
773 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
774 debugstr_w(psub
->to
.name
));
779 static LPWSTR
strdupW(LPCWSTR p
)
782 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
783 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
788 static LPSTR
strdupA(LPCSTR p
)
791 DWORD len
= (strlen(p
) + 1);
792 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
797 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
802 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
804 if(!strcmpiW(element
->from
.name
, from_name
) &&
805 (element
->from
.charset
== from_charset
||
806 element
->from
.charset
== -1))
813 #define ADD_FONT_SUBST_FORCE 1
815 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
817 FontSubst
*from_exist
, *to_exist
;
819 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
821 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
823 list_remove(&from_exist
->entry
);
824 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
825 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
826 HeapFree(GetProcessHeap(), 0, from_exist
);
832 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
836 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
837 subst
->to
.name
= strdupW(to_exist
->to
.name
);
840 list_add_tail(subst_list
, &subst
->entry
);
845 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
846 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
847 HeapFree(GetProcessHeap(), 0, subst
);
851 static void split_subst_info(NameCs
*nc
, LPSTR str
)
853 CHAR
*p
= strrchr(str
, ',');
858 nc
->charset
= strtol(p
+1, NULL
, 10);
861 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
862 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
863 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
866 static void LoadSubstList(void)
870 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
874 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
875 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
876 &hkey
) == ERROR_SUCCESS
) {
878 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
879 &valuelen
, &datalen
, NULL
, NULL
);
881 valuelen
++; /* returned value doesn't include room for '\0' */
882 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
883 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
887 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
888 &dlen
) == ERROR_SUCCESS
) {
889 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
891 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
892 split_subst_info(&psub
->from
, value
);
893 split_subst_info(&psub
->to
, data
);
895 /* Win 2000 doesn't allow mapping between different charsets
896 or mapping of DEFAULT_CHARSET */
897 if((psub
->to
.charset
!= psub
->from
.charset
) ||
898 psub
->to
.charset
== DEFAULT_CHARSET
) {
899 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
900 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
901 HeapFree(GetProcessHeap(), 0, psub
);
903 add_font_subst(&font_subst_list
, psub
, 0);
905 /* reset dlen and vlen */
909 HeapFree(GetProcessHeap(), 0, data
);
910 HeapFree(GetProcessHeap(), 0, value
);
915 static WCHAR
*get_familyname(FT_Face ft_face
)
917 WCHAR
*family
= NULL
;
919 FT_UInt num_names
, name_index
, i
;
921 if(FT_IS_SFNT(ft_face
))
923 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
925 for(name_index
= 0; name_index
< num_names
; name_index
++)
927 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
929 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
930 (name
.language_id
== GetUserDefaultLCID()) &&
931 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
932 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
934 /* String is not nul terminated and string_len is a byte length. */
935 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
936 for(i
= 0; i
< name
.string_len
/ 2; i
++)
938 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
939 family
[i
] = GET_BE_WORD(*tmp
);
943 TRACE("Got localised name %s\n", debugstr_w(family
));
954 #define ADDFONT_EXTERNAL_FONT 0x01
955 #define ADDFONT_FORCE_BITMAP 0x02
956 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
960 TT_Header
*pHeader
= NULL
;
961 WCHAR
*english_family
, *localised_family
, *StyleW
;
965 struct list
*family_elem_ptr
, *face_elem_ptr
;
967 FT_Long face_index
= 0, num_faces
;
968 #ifdef HAVE_FREETYPE_FTWINFNT_H
969 FT_WinFNT_HeaderRec winfnt_header
;
971 int i
, bitmap_num
, internal_leading
;
974 #ifdef HAVE_CARBON_CARBON_H
977 char **mac_list
= expand_mac_font(file
);
980 BOOL had_one
= FALSE
;
982 for(cursor
= mac_list
; *cursor
; cursor
++)
985 AddFontFileToList(*cursor
, NULL
, NULL
, flags
);
986 HeapFree(GetProcessHeap(), 0, *cursor
);
988 HeapFree(GetProcessHeap(), 0, mac_list
);
993 #endif /* HAVE_CARBON_CARBON_H */
996 char *family_name
= fake_family
;
998 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
999 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
1000 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
1004 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*/
1005 WARN("Ignoring font %s\n", debugstr_a(file
));
1006 pFT_Done_Face(ft_face
);
1010 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1011 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1012 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file
));
1013 pFT_Done_Face(ft_face
);
1017 if(FT_IS_SFNT(ft_face
) && (!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
1018 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1019 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))) {
1020 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1021 "Skipping this font.\n", debugstr_a(file
));
1022 pFT_Done_Face(ft_face
);
1026 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1027 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
1028 pFT_Done_Face(ft_face
);
1034 localised_family
= get_familyname(ft_face
);
1035 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1037 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1038 HeapFree(GetProcessHeap(), 0, localised_family
);
1039 num_faces
= ft_face
->num_faces
;
1040 pFT_Done_Face(ft_face
);
1043 HeapFree(GetProcessHeap(), 0, localised_family
);
1047 family_name
= ft_face
->family_name
;
1051 My_FT_Bitmap_Size
*size
= NULL
;
1053 if(!FT_IS_SCALABLE(ft_face
))
1054 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1056 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1057 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1058 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1060 localised_family
= NULL
;
1062 localised_family
= get_familyname(ft_face
);
1063 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1064 HeapFree(GetProcessHeap(), 0, localised_family
);
1065 localised_family
= NULL
;
1070 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1071 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1072 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1077 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1078 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1079 list_init(&family
->faces
);
1080 list_add_tail(&font_list
, &family
->entry
);
1082 if(localised_family
) {
1083 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1084 subst
->from
.name
= strdupW(english_family
);
1085 subst
->from
.charset
= -1;
1086 subst
->to
.name
= strdupW(localised_family
);
1087 subst
->to
.charset
= -1;
1088 add_font_subst(&font_subst_list
, subst
, 0);
1091 HeapFree(GetProcessHeap(), 0, localised_family
);
1092 HeapFree(GetProcessHeap(), 0, english_family
);
1094 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1095 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1096 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1098 internal_leading
= 0;
1099 memset(&fs
, 0, sizeof(fs
));
1101 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1103 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1104 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1105 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1106 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1107 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1108 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1109 if(pOS2
->version
== 0) {
1112 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1115 fs
.fsCsb
[0] |= 1L << 31;
1118 #ifdef HAVE_FREETYPE_FTWINFNT_H
1119 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1121 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1122 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1123 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1124 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
1125 internal_leading
= winfnt_header
.internal_leading
;
1129 face_elem_ptr
= list_head(&family
->faces
);
1130 while(face_elem_ptr
) {
1131 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1132 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1133 if(!strcmpW(face
->StyleName
, StyleW
) &&
1134 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1135 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1136 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1137 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1140 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1141 HeapFree(GetProcessHeap(), 0, StyleW
);
1142 pFT_Done_Face(ft_face
);
1145 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1146 TRACE("Original font is newer so skipping this one\n");
1147 HeapFree(GetProcessHeap(), 0, StyleW
);
1148 pFT_Done_Face(ft_face
);
1151 TRACE("Replacing original with this one\n");
1152 list_remove(&face
->entry
);
1153 HeapFree(GetProcessHeap(), 0, face
->file
);
1154 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1155 HeapFree(GetProcessHeap(), 0, face
);
1160 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1161 list_add_tail(&family
->faces
, &face
->entry
);
1162 face
->StyleName
= StyleW
;
1163 face
->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
1164 strcpy(face
->file
, file
);
1165 face
->face_index
= face_index
;
1166 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
1167 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
1168 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1169 face
->family
= family
;
1170 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1171 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
1172 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1174 if(FT_IS_SCALABLE(ft_face
)) {
1175 memset(&face
->size
, 0, sizeof(face
->size
));
1176 face
->scalable
= TRUE
;
1178 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1179 size
->height
, size
->width
, size
->size
>> 6,
1180 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1181 face
->size
.height
= size
->height
;
1182 face
->size
.width
= size
->width
;
1183 face
->size
.size
= size
->size
;
1184 face
->size
.x_ppem
= size
->x_ppem
;
1185 face
->size
.y_ppem
= size
->y_ppem
;
1186 face
->size
.internal_leading
= internal_leading
;
1187 face
->scalable
= FALSE
;
1190 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1191 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1192 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1193 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1196 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1197 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1198 switch(ft_face
->charmaps
[i
]->encoding
) {
1199 case FT_ENCODING_UNICODE
:
1200 case FT_ENCODING_APPLE_ROMAN
:
1201 face
->fs
.fsCsb
[0] |= 1;
1203 case FT_ENCODING_MS_SYMBOL
:
1204 face
->fs
.fsCsb
[0] |= 1L << 31;
1212 if(face
->fs
.fsCsb
[0] & ~(1L << 31))
1213 have_installed_roman_font
= TRUE
;
1214 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1216 num_faces
= ft_face
->num_faces
;
1217 pFT_Done_Face(ft_face
);
1218 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1219 debugstr_w(StyleW
));
1220 } while(num_faces
> ++face_index
);
1224 static void DumpFontList(void)
1228 struct list
*family_elem_ptr
, *face_elem_ptr
;
1230 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1231 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1232 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1233 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1234 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1235 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1237 TRACE(" %d", face
->size
.height
);
1244 /***********************************************************
1245 * The replacement list is a way to map an entire font
1246 * family onto another family. For example adding
1248 * [HKCU\Software\Wine\Fonts\Replacements]
1249 * "Wingdings"="Winedings"
1251 * would enumerate the Winedings font both as Winedings and
1252 * Wingdings. However if a real Wingdings font is present the
1253 * replacement does not take place.
1256 static void LoadReplaceList(void)
1259 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1264 struct list
*family_elem_ptr
, *face_elem_ptr
;
1267 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1268 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1270 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1271 &valuelen
, &datalen
, NULL
, NULL
);
1273 valuelen
++; /* returned value doesn't include room for '\0' */
1274 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1275 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1279 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1280 &dlen
) == ERROR_SUCCESS
) {
1281 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1282 /* "NewName"="Oldname" */
1283 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1285 /* Find the old family and hence all of the font files
1287 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1288 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1289 if(!strcmpiW(family
->FamilyName
, data
)) {
1290 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1291 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1292 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1293 debugstr_w(face
->StyleName
), familyA
);
1294 /* Now add a new entry with the new family name */
1295 AddFontFileToList(face
->file
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1300 /* reset dlen and vlen */
1304 HeapFree(GetProcessHeap(), 0, data
);
1305 HeapFree(GetProcessHeap(), 0, value
);
1310 /*************************************************************
1313 static BOOL
init_system_links(void)
1315 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1316 'W','i','n','d','o','w','s',' ','N','T','\\',
1317 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1318 'S','y','s','t','e','m','L','i','n','k',0};
1321 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1322 WCHAR
*value
, *data
;
1323 WCHAR
*entry
, *next
;
1324 SYSTEM_LINKS
*font_link
, *system_font_link
;
1325 CHILD_FONT
*child_font
;
1326 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1327 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1328 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1334 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1336 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1337 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1338 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1339 val_len
= max_val
+ 1;
1340 data_len
= max_data
;
1342 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1344 TRACE("%s:\n", debugstr_w(value
));
1346 memset(&fs
, 0, sizeof(fs
));
1347 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1348 psub
= get_font_subst(&font_subst_list
, value
, -1);
1349 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1350 list_init(&font_link
->links
);
1351 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1354 CHILD_FONT
*child_font
;
1356 TRACE("\t%s\n", debugstr_w(entry
));
1358 next
= entry
+ strlenW(entry
) + 1;
1360 face_name
= strchrW(entry
, ',');
1364 while(isspaceW(*face_name
))
1367 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1369 face_name
= psub
->to
.name
;
1371 face
= find_face_from_filename(entry
, face_name
);
1374 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1378 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1379 child_font
->file_name
= strdupA(face
->file
);
1380 child_font
->index
= face
->face_index
;
1381 child_font
->font
= NULL
;
1382 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1383 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1384 TRACE("Adding file %s index %d\n", child_font
->file_name
, child_font
->index
);
1385 list_add_tail(&font_link
->links
, &child_font
->entry
);
1387 family
= find_family_from_name(font_link
->font_name
);
1390 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1392 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
1395 list_add_tail(&system_links
, &font_link
->entry
);
1396 val_len
= max_val
+ 1;
1397 data_len
= max_data
;
1400 HeapFree(GetProcessHeap(), 0, value
);
1401 HeapFree(GetProcessHeap(), 0, data
);
1405 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1408 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1409 system_font_link
->font_name
= strdupW(System
);
1410 list_init(&system_font_link
->links
);
1412 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1415 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1416 child_font
->file_name
= strdupA(face
->file
);
1417 child_font
->index
= face
->face_index
;
1418 child_font
->font
= NULL
;
1419 TRACE("Found Tahoma in %s index %d\n", child_font
->file_name
, child_font
->index
);
1420 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1422 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1424 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1426 CHILD_FONT
*font_link_entry
;
1427 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1429 CHILD_FONT
*new_child
;
1430 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1431 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
1432 new_child
->index
= font_link_entry
->index
;
1433 new_child
->font
= NULL
;
1434 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1439 list_add_tail(&system_links
, &system_font_link
->entry
);
1443 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1446 struct dirent
*dent
;
1447 char path
[MAX_PATH
];
1449 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1451 dir
= opendir(dirname
);
1453 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1456 while((dent
= readdir(dir
)) != NULL
) {
1457 struct stat statbuf
;
1459 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1462 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1464 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1466 if(stat(path
, &statbuf
) == -1)
1468 WARN("Can't stat %s\n", debugstr_a(path
));
1471 if(S_ISDIR(statbuf
.st_mode
))
1472 ReadFontDir(path
, external_fonts
);
1474 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1480 static void load_fontconfig_fonts(void)
1482 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1483 void *fc_handle
= NULL
;
1492 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1494 TRACE("Wine cannot find the fontconfig library (%s).\n",
1495 SONAME_LIBFONTCONFIG
);
1498 #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;}
1499 LOAD_FUNCPTR(FcConfigGetCurrent
);
1500 LOAD_FUNCPTR(FcFontList
);
1501 LOAD_FUNCPTR(FcFontSetDestroy
);
1502 LOAD_FUNCPTR(FcInit
);
1503 LOAD_FUNCPTR(FcObjectSetAdd
);
1504 LOAD_FUNCPTR(FcObjectSetCreate
);
1505 LOAD_FUNCPTR(FcObjectSetDestroy
);
1506 LOAD_FUNCPTR(FcPatternCreate
);
1507 LOAD_FUNCPTR(FcPatternDestroy
);
1508 LOAD_FUNCPTR(FcPatternGetBool
);
1509 LOAD_FUNCPTR(FcPatternGetString
);
1512 if(!pFcInit()) return;
1514 config
= pFcConfigGetCurrent();
1515 pat
= pFcPatternCreate();
1516 os
= pFcObjectSetCreate();
1517 pFcObjectSetAdd(os
, FC_FILE
);
1518 pFcObjectSetAdd(os
, FC_SCALABLE
);
1519 fontset
= pFcFontList(config
, pat
, os
);
1520 if(!fontset
) return;
1521 for(i
= 0; i
< fontset
->nfont
; i
++) {
1524 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1526 TRACE("fontconfig: %s\n", file
);
1528 /* We're just interested in OT/TT fonts for now, so this hack just
1529 picks up the scalable fonts without extensions .pf[ab] to save time
1530 loading every other font */
1532 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1534 TRACE("not scalable\n");
1538 len
= strlen( file
);
1539 if(len
< 4) continue;
1540 ext
= &file
[ len
- 3 ];
1541 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1542 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1544 pFcFontSetDestroy(fontset
);
1545 pFcObjectSetDestroy(os
);
1546 pFcPatternDestroy(pat
);
1552 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1555 const char *data_dir
= wine_get_data_dir();
1557 if (!data_dir
) data_dir
= wine_get_build_dir();
1564 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1566 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1568 strcpy(unix_name
, data_dir
);
1569 strcat(unix_name
, "/fonts/");
1571 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1573 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1574 HeapFree(GetProcessHeap(), 0, unix_name
);
1579 static void load_system_fonts(void)
1582 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1583 const WCHAR
* const *value
;
1585 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1588 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1589 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1590 strcatW(windowsdir
, fontsW
);
1591 for(value
= SystemFontValues
; *value
; value
++) {
1592 dlen
= sizeof(data
);
1593 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1597 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1598 if((unixname
= wine_get_unix_file_name(pathW
))) {
1599 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1600 HeapFree(GetProcessHeap(), 0, unixname
);
1603 load_font_from_data_dir(data
);
1610 /*************************************************************
1612 * This adds registry entries for any externally loaded fonts
1613 * (fonts from fontconfig or FontDirs). It also deletes entries
1614 * of no longer existing fonts.
1617 static void update_reg_entries(void)
1619 HKEY winkey
= 0, externalkey
= 0;
1622 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
1625 struct list
*family_elem_ptr
, *face_elem_ptr
;
1627 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1628 static const WCHAR spaceW
[] = {' ', '\0'};
1631 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1632 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
1633 ERR("Can't create Windows font reg key\n");
1636 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1637 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
1638 ERR("Can't create external font reg key\n");
1642 /* Delete all external fonts added last time */
1644 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1645 &valuelen
, &datalen
, NULL
, NULL
);
1646 valuelen
++; /* returned value doesn't include room for '\0' */
1647 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1648 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1650 dlen
= datalen
* sizeof(WCHAR
);
1653 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1654 &dlen
) == ERROR_SUCCESS
) {
1656 RegDeleteValueW(winkey
, valueW
);
1657 /* reset dlen and vlen */
1661 HeapFree(GetProcessHeap(), 0, data
);
1662 HeapFree(GetProcessHeap(), 0, valueW
);
1664 /* Delete the old external fonts key */
1665 RegCloseKey(externalkey
);
1667 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1669 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1670 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1671 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
1672 ERR("Can't create external font reg key\n");
1676 /* enumerate the fonts and add external ones to the two keys */
1678 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1679 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1680 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1681 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1682 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1683 if(!face
->external
) continue;
1685 if(strcmpiW(face
->StyleName
, RegularW
))
1686 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1687 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1688 strcpyW(valueW
, family
->FamilyName
);
1689 if(len
!= len_fam
) {
1690 strcatW(valueW
, spaceW
);
1691 strcatW(valueW
, face
->StyleName
);
1693 strcatW(valueW
, TrueType
);
1694 if((path
= strrchr(face
->file
, '/')) == NULL
)
1698 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1700 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1701 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1702 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1703 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1705 HeapFree(GetProcessHeap(), 0, file
);
1706 HeapFree(GetProcessHeap(), 0, valueW
);
1711 RegCloseKey(externalkey
);
1713 RegCloseKey(winkey
);
1718 /*************************************************************
1719 * WineEngAddFontResourceEx
1722 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1724 if (ft_handle
) /* do it only if we have freetype up and running */
1729 FIXME("Ignoring flags %x\n", flags
);
1731 if((unixname
= wine_get_unix_file_name(file
)))
1733 INT ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1734 HeapFree(GetProcessHeap(), 0, unixname
);
1741 /*************************************************************
1742 * WineEngRemoveFontResourceEx
1745 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1751 static const struct nls_update_font_list
1753 UINT ansi_cp
, oem_cp
;
1754 const char *oem
, *fixed
, *system
;
1755 const char *courier
, *serif
, *small
, *sserif
;
1756 /* these are for font substitute */
1757 const char *shelldlg
, *tmsrmn
;
1758 } nls_update_font_list
[] =
1760 /* Latin 1 (United States) */
1761 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1762 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1763 "Tahoma","Times New Roman",
1765 /* Latin 1 (Multilingual) */
1766 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1767 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1768 "Tahoma","Times New Roman", /* FIXME unverified */
1770 /* Eastern Europe */
1771 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1772 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1773 "Tahoma","Times New Roman", /* FIXME unverified */
1776 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1777 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1778 "Tahoma","Times New Roman", /* FIXME unverified */
1781 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1782 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1783 "Tahoma","Times New Roman", /* FIXME unverified */
1786 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1787 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1788 "Tahoma","Times New Roman", /* FIXME unverified */
1791 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1792 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1793 "Tahoma","Times New Roman", /* FIXME unverified */
1796 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1797 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1798 "Tahoma","Times New Roman", /* FIXME unverified */
1801 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1802 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1803 "Tahoma","Times New Roman", /* FIXME unverified */
1806 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1807 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1808 "Tahoma","Times New Roman", /* FIXME unverified */
1811 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1812 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1813 "Tahoma","Times New Roman", /* FIXME unverified */
1816 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1817 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1818 "MS UI Gothic","MS Serif",
1820 /* Chinese Simplified */
1821 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1822 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1823 "Tahoma", "Times New Roman", /* FIXME unverified */
1826 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1827 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1830 /* Chinese Traditional */
1831 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1832 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1833 "Tahoma", "Times New Roman", /* FIXME unverified */
1837 static inline HKEY
create_fonts_NT_registry_key(void)
1841 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
1842 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1846 static inline HKEY
create_fonts_9x_registry_key(void)
1850 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
1851 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1855 static inline HKEY
create_config_fonts_registry_key(void)
1859 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
1860 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1864 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
1866 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
1867 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
1868 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
1869 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
1872 static void update_font_info(void)
1874 char buf
[40], cpbuf
[40];
1877 UINT i
, ansi_cp
= 0, oem_cp
= 0;
1879 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
1882 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1883 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
1884 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1885 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
1886 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
1889 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
1891 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
1896 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
1898 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
1900 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
1903 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
1905 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
1906 nls_update_font_list
[i
].oem_cp
== oem_cp
)
1910 hkey
= create_config_fonts_registry_key();
1911 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
1912 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
1913 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
1916 hkey
= create_fonts_NT_registry_key();
1917 add_font_list(hkey
, &nls_update_font_list
[i
]);
1920 hkey
= create_fonts_9x_registry_key();
1921 add_font_list(hkey
, &nls_update_font_list
[i
]);
1924 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
1926 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
1927 strlen(nls_update_font_list
[i
].shelldlg
)+1);
1928 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
1929 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
1935 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
1938 /*************************************************************
1941 * Initialize FreeType library and create a list of available faces
1943 BOOL
WineEngInit(void)
1945 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
1946 static const WCHAR pathW
[] = {'P','a','t','h',0};
1948 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1950 WCHAR windowsdir
[MAX_PATH
];
1953 const char *data_dir
;
1957 /* update locale dependent font info in registry */
1960 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
1963 "Wine cannot find the FreeType font library. To enable Wine to\n"
1964 "use TrueType fonts please install a version of FreeType greater than\n"
1965 "or equal to 2.0.5.\n"
1966 "http://www.freetype.org\n");
1970 #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;}
1972 LOAD_FUNCPTR(FT_Vector_Unit
)
1973 LOAD_FUNCPTR(FT_Done_Face
)
1974 LOAD_FUNCPTR(FT_Get_Char_Index
)
1975 LOAD_FUNCPTR(FT_Get_Module
)
1976 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
1977 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
1978 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1979 LOAD_FUNCPTR(FT_Init_FreeType
)
1980 LOAD_FUNCPTR(FT_Load_Glyph
)
1981 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1982 LOAD_FUNCPTR(FT_MulFix
)
1983 LOAD_FUNCPTR(FT_New_Face
)
1984 LOAD_FUNCPTR(FT_New_Memory_Face
)
1985 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1986 LOAD_FUNCPTR(FT_Outline_Transform
)
1987 LOAD_FUNCPTR(FT_Outline_Translate
)
1988 LOAD_FUNCPTR(FT_Select_Charmap
)
1989 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1990 LOAD_FUNCPTR(FT_Vector_Transform
)
1993 /* Don't warn if this one is missing */
1994 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
1995 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
1996 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
1997 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
1998 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
1999 #ifdef HAVE_FREETYPE_FTWINFNT_H
2000 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2002 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2003 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2004 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2005 <= 2.0.3 has FT_Sqrt64 */
2009 if(pFT_Init_FreeType(&library
) != 0) {
2010 ERR("Can't init FreeType library\n");
2011 wine_dlclose(ft_handle
, NULL
, 0);
2015 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
2016 if (pFT_Library_Version
)
2018 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2020 if (FT_Version
.major
<=0)
2026 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2027 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2028 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2029 ((FT_Version
.patch
) & 0x0000ff);
2031 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2032 ERR("Failed to create font mutex\n");
2035 WaitForSingleObject(font_mutex
, INFINITE
);
2037 /* load the system bitmap fonts */
2038 load_system_fonts();
2040 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2041 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2042 strcatW(windowsdir
, fontsW
);
2043 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2045 ReadFontDir(unixname
, FALSE
);
2046 HeapFree(GetProcessHeap(), 0, unixname
);
2049 /* load the system truetype fonts */
2050 data_dir
= wine_get_data_dir();
2051 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2052 strcpy(unixname
, data_dir
);
2053 strcat(unixname
, "/fonts/");
2054 ReadFontDir(unixname
, FALSE
);
2055 HeapFree(GetProcessHeap(), 0, unixname
);
2058 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2059 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2060 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2062 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2063 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2064 &hkey
) == ERROR_SUCCESS
) {
2066 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2067 &valuelen
, &datalen
, NULL
, NULL
);
2069 valuelen
++; /* returned value doesn't include room for '\0' */
2070 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2071 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2074 dlen
= datalen
* sizeof(WCHAR
);
2076 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2077 &dlen
) == ERROR_SUCCESS
) {
2078 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2080 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2082 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2083 HeapFree(GetProcessHeap(), 0, unixname
);
2086 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2088 WCHAR pathW
[MAX_PATH
];
2089 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2092 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2093 if((unixname
= wine_get_unix_file_name(pathW
)))
2095 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2096 HeapFree(GetProcessHeap(), 0, unixname
);
2099 load_font_from_data_dir(data
);
2101 /* reset dlen and vlen */
2106 HeapFree(GetProcessHeap(), 0, data
);
2107 HeapFree(GetProcessHeap(), 0, valueW
);
2111 load_fontconfig_fonts();
2113 /* then look in any directories that we've specified in the config file */
2114 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2115 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2121 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2123 len
+= sizeof(WCHAR
);
2124 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2125 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2127 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2128 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2129 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2130 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2134 LPSTR next
= strchr( ptr
, ':' );
2135 if (next
) *next
++ = 0;
2136 ReadFontDir( ptr
, TRUE
);
2139 HeapFree( GetProcessHeap(), 0, valueA
);
2141 HeapFree( GetProcessHeap(), 0, valueW
);
2150 update_reg_entries();
2152 init_system_links();
2154 ReleaseMutex(font_mutex
);
2158 "Wine cannot find certain functions that it needs inside the FreeType\n"
2159 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2160 "FreeType to at least version 2.0.5.\n"
2161 "http://www.freetype.org\n");
2162 wine_dlclose(ft_handle
, NULL
, 0);
2168 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2171 TT_HoriHeader
*pHori
;
2175 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2176 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2178 if(height
== 0) height
= 16;
2180 /* Calc. height of EM square:
2182 * For +ve lfHeight we have
2183 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2184 * Re-arranging gives:
2185 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2187 * For -ve lfHeight we have
2189 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2190 * with il = winAscent + winDescent - units_per_em]
2195 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2196 ppem
= ft_face
->units_per_EM
* height
/
2197 (pHori
->Ascender
- pHori
->Descender
);
2199 ppem
= ft_face
->units_per_EM
* height
/
2200 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2208 static struct font_mapping
*map_font( const char *name
)
2210 struct font_mapping
*mapping
;
2214 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2215 if (fstat( fd
, &st
) == -1) goto error
;
2217 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2219 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2221 mapping
->refcount
++;
2226 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2229 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2232 if (mapping
->data
== MAP_FAILED
)
2234 HeapFree( GetProcessHeap(), 0, mapping
);
2237 mapping
->refcount
= 1;
2238 mapping
->dev
= st
.st_dev
;
2239 mapping
->ino
= st
.st_ino
;
2240 mapping
->size
= st
.st_size
;
2241 list_add_tail( &mappings_list
, &mapping
->entry
);
2249 static void unmap_font( struct font_mapping
*mapping
)
2251 if (!--mapping
->refcount
)
2253 list_remove( &mapping
->entry
);
2254 munmap( mapping
->data
, mapping
->size
);
2255 HeapFree( GetProcessHeap(), 0, mapping
);
2259 static LONG
load_VDMX(GdiFont
*, LONG
);
2261 static FT_Face
OpenFontFile(GdiFont
*font
, char *file
, FT_Long face_index
, LONG width
, LONG height
)
2266 TRACE("%s, %ld, %d x %d\n", debugstr_a(file
), face_index
, width
, height
);
2268 if (!(font
->mapping
= map_font( file
)))
2270 WARN("failed to map %s\n", debugstr_a(file
));
2274 err
= pFT_New_Memory_Face(library
, font
->mapping
->data
, font
->mapping
->size
, face_index
, &ft_face
);
2276 ERR("FT_New_Face rets %d\n", err
);
2280 /* set it here, as load_VDMX needs it */
2281 font
->ft_face
= ft_face
;
2283 if(FT_IS_SCALABLE(ft_face
)) {
2284 /* load the VDMX table if we have one */
2285 font
->ppem
= load_VDMX(font
, height
);
2287 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2289 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2290 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2292 font
->ppem
= height
;
2293 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2294 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2300 static int get_nearest_charset(Face
*face
, int *cp
)
2302 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2303 a single face with the requested charset. The idea is to check if
2304 the selected font supports the current ANSI codepage, if it does
2305 return the corresponding charset, else return the first charset */
2308 int acp
= GetACP(), i
;
2312 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2313 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2314 return csi
.ciCharset
;
2316 for(i
= 0; i
< 32; i
++) {
2318 if(face
->fs
.fsCsb
[0] & fs0
) {
2319 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2321 return csi
.ciCharset
;
2324 FIXME("TCI failing on %x\n", fs0
);
2328 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2329 face
->fs
.fsCsb
[0], face
->file
);
2331 return DEFAULT_CHARSET
;
2334 static GdiFont
*alloc_font(void)
2336 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2337 ret
->gmsize
= INIT_GM_SIZE
;
2338 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
2339 ret
->gmsize
* sizeof(*ret
->gm
));
2341 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2342 ret
->total_kern_pairs
= (DWORD
)-1;
2343 ret
->kern_pairs
= NULL
;
2344 list_init(&ret
->hfontlist
);
2345 list_init(&ret
->child_fonts
);
2349 static void free_font(GdiFont
*font
)
2351 struct list
*cursor
, *cursor2
;
2353 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2355 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2356 struct list
*first_hfont
;
2357 HFONTLIST
*hfontlist
;
2358 list_remove(cursor
);
2361 first_hfont
= list_head(&child
->font
->hfontlist
);
2362 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2363 DeleteObject(hfontlist
->hfont
);
2364 HeapFree(GetProcessHeap(), 0, hfontlist
);
2365 free_font(child
->font
);
2367 HeapFree(GetProcessHeap(), 0, child
->file_name
);
2368 HeapFree(GetProcessHeap(), 0, child
);
2371 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2372 if (font
->mapping
) unmap_font( font
->mapping
);
2373 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2374 HeapFree(GetProcessHeap(), 0, font
->potm
);
2375 HeapFree(GetProcessHeap(), 0, font
->name
);
2376 HeapFree(GetProcessHeap(), 0, font
->gm
);
2377 HeapFree(GetProcessHeap(), 0, font
);
2381 /*************************************************************
2384 * load the vdmx entry for the specified height
2387 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2388 ( ( (FT_ULong)_x4 << 24 ) | \
2389 ( (FT_ULong)_x3 << 16 ) | \
2390 ( (FT_ULong)_x2 << 8 ) | \
2393 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2408 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2412 BYTE devXRatio
, devYRatio
;
2413 USHORT numRecs
, numRatios
;
2414 DWORD result
, offset
= -1;
2418 /* For documentation on VDMX records, see
2419 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2422 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2424 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2427 /* FIXME: need the real device aspect ratio */
2431 numRecs
= GET_BE_WORD(hdr
[1]);
2432 numRatios
= GET_BE_WORD(hdr
[2]);
2434 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2435 for(i
= 0; i
< numRatios
; i
++) {
2438 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2439 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2442 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2444 if((ratio
.xRatio
== 0 &&
2445 ratio
.yStartRatio
== 0 &&
2446 ratio
.yEndRatio
== 0) ||
2447 (devXRatio
== ratio
.xRatio
&&
2448 devYRatio
>= ratio
.yStartRatio
&&
2449 devYRatio
<= ratio
.yEndRatio
))
2451 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2452 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2453 offset
= GET_BE_WORD(tmp
);
2459 FIXME("No suitable ratio found\n");
2463 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2465 BYTE startsz
, endsz
;
2468 recs
= GET_BE_WORD(group
.recs
);
2469 startsz
= group
.startsz
;
2470 endsz
= group
.endsz
;
2472 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2474 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2475 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2476 if(result
== GDI_ERROR
) {
2477 FIXME("Failed to retrieve vTable\n");
2482 for(i
= 0; i
< recs
; i
++) {
2483 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2484 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2485 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2487 if(yMax
+ -yMin
== height
) {
2490 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2493 if(yMax
+ -yMin
> height
) {
2496 goto end
; /* failed */
2498 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2499 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2500 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2501 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2507 TRACE("ppem not found for height %d\n", height
);
2511 if(ppem
< startsz
|| ppem
> endsz
)
2514 for(i
= 0; i
< recs
; i
++) {
2516 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2518 if(yPelHeight
> ppem
)
2521 if(yPelHeight
== ppem
) {
2522 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2523 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2524 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2530 HeapFree(GetProcessHeap(), 0, vTable
);
2536 static BOOL
fontcmp(GdiFont
*font
, FONT_DESC
*fd
)
2538 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2539 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2540 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2541 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2542 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2545 static void calc_hash(FONT_DESC
*pfd
)
2547 DWORD hash
= 0, *ptr
, two_chars
;
2551 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2553 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2555 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2557 pwc
= (WCHAR
*)&two_chars
;
2559 *pwc
= toupperW(*pwc
);
2561 *pwc
= toupperW(*pwc
);
2565 hash
^= !pfd
->can_use_bitmap
;
2570 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2575 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2577 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
2578 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2579 fd
.can_use_bitmap
= can_use_bitmap
;
2582 /* try the in-use list */
2583 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2584 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2585 if(!fontcmp(ret
, &fd
)) {
2586 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2587 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2588 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2589 if(hflist
->hfont
== hfont
)
2592 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2593 hflist
->hfont
= hfont
;
2594 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2599 /* then the unused list */
2600 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2601 while(font_elem_ptr
) {
2602 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2603 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2604 if(!fontcmp(ret
, &fd
)) {
2605 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2606 assert(list_empty(&ret
->hfontlist
));
2607 TRACE("Found %p in unused list\n", ret
);
2608 list_remove(&ret
->entry
);
2609 list_add_head(&gdi_font_list
, &ret
->entry
);
2610 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2611 hflist
->hfont
= hfont
;
2612 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2620 /*************************************************************
2621 * create_child_font_list
2623 static BOOL
create_child_font_list(GdiFont
*font
)
2626 SYSTEM_LINKS
*font_link
;
2627 CHILD_FONT
*font_link_entry
, *new_child
;
2629 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2631 if(!strcmpW(font_link
->font_name
, font
->name
))
2633 TRACE("found entry in system list\n");
2634 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2636 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2637 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
2638 new_child
->index
= font_link_entry
->index
;
2639 new_child
->font
= NULL
;
2640 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2641 TRACE("font %s %d\n", debugstr_a(new_child
->file_name
), new_child
->index
);
2651 /*************************************************************
2652 * WineEngCreateFontInstance
2655 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2658 Face
*face
, *best
, *best_bitmap
;
2659 Family
*family
, *last_resort_family
;
2660 struct list
*family_elem_ptr
, *face_elem_ptr
;
2661 INT height
, width
= 0;
2662 unsigned int score
= 0, new_score
;
2663 signed int diff
= 0, newdiff
;
2664 BOOL bd
, it
, can_use_bitmap
;
2669 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2671 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2672 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2673 if(hflist
->hfont
== hfont
)
2677 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
2678 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2680 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2681 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2682 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2685 /* check the cache first */
2686 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2687 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2691 TRACE("not in cache\n");
2692 if(list_empty(&font_list
)) /* No fonts installed */
2694 TRACE("No fonts installed\n");
2697 if(!have_installed_roman_font
)
2699 TRACE("No roman font installed\n");
2705 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
2706 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
2707 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
2708 calc_hash(&ret
->font_desc
);
2709 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2710 hflist
->hfont
= hfont
;
2711 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2714 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2715 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2716 original value lfCharSet. Note this is a special case for
2717 Symbol and doesn't happen at least for "Wingdings*" */
2719 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
2720 lf
.lfCharSet
= SYMBOL_CHARSET
;
2722 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
2723 switch(lf
.lfCharSet
) {
2724 case DEFAULT_CHARSET
:
2725 csi
.fs
.fsCsb
[0] = 0;
2728 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
2729 csi
.fs
.fsCsb
[0] = 0;
2735 if(lf
.lfFaceName
[0] != '\0') {
2737 SYSTEM_LINKS
*font_link
;
2738 CHILD_FONT
*font_link_entry
;
2740 psub
= get_font_subst(&font_subst_list
, lf
.lfFaceName
, lf
.lfCharSet
);
2743 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
2744 debugstr_w(psub
->to
.name
));
2745 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2748 /* We want a match on name and charset or just name if
2749 charset was DEFAULT_CHARSET. If the latter then
2750 we fixup the returned charset later in get_nearest_charset
2751 where we'll either use the charset of the current ansi codepage
2752 or if that's unavailable the first charset that the font supports.
2754 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2755 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2756 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2757 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2758 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2759 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2760 if(face
->scalable
|| can_use_bitmap
)
2767 * Try check the SystemLink list first for a replacement font.
2768 * We may find good replacements there.
2770 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2772 if(!strcmpiW(font_link
->font_name
, lf
.lfFaceName
))
2774 TRACE("found entry in system list\n");
2775 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2777 face
= find_face_from_path_index(font_link_entry
->file_name
,
2778 font_link_entry
->index
);
2781 family
= face
->family
;
2782 if(csi
.fs
.fsCsb
[0] &
2783 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
2785 if(face
->scalable
|| can_use_bitmap
)
2794 /* If requested charset was DEFAULT_CHARSET then try using charset
2795 corresponding to the current ansi codepage */
2796 if(!csi
.fs
.fsCsb
[0]) {
2798 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
2799 FIXME("TCI failed on codepage %d\n", acp
);
2800 csi
.fs
.fsCsb
[0] = 0;
2802 lf
.lfCharSet
= csi
.ciCharset
;
2805 /* Face families are in the top 4 bits of lfPitchAndFamily,
2806 so mask with 0xF0 before testing */
2808 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
2809 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
2810 strcpyW(lf
.lfFaceName
, defFixed
);
2811 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
2812 strcpyW(lf
.lfFaceName
, defSerif
);
2813 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
2814 strcpyW(lf
.lfFaceName
, defSans
);
2816 strcpyW(lf
.lfFaceName
, defSans
);
2817 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2818 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2819 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2820 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2821 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2822 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2823 if(face
->scalable
|| can_use_bitmap
)
2829 last_resort_family
= NULL
;
2830 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2831 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2832 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2833 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2834 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
2837 if(can_use_bitmap
&& !last_resort_family
)
2838 last_resort_family
= family
;
2843 if(last_resort_family
) {
2844 family
= last_resort_family
;
2845 csi
.fs
.fsCsb
[0] = 0;
2849 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2850 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2851 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2852 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2853 if(face
->scalable
) {
2854 csi
.fs
.fsCsb
[0] = 0;
2855 WARN("just using first face for now\n");
2858 if(can_use_bitmap
&& !last_resort_family
)
2859 last_resort_family
= family
;
2862 if(!last_resort_family
) {
2863 FIXME("can't find a single appropriate font - bailing\n");
2868 WARN("could only find a bitmap font - this will probably look awful!\n");
2869 family
= last_resort_family
;
2870 csi
.fs
.fsCsb
[0] = 0;
2873 it
= lf
.lfItalic
? 1 : 0;
2874 bd
= lf
.lfWeight
> 550 ? 1 : 0;
2876 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
2877 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
2879 face
= best
= best_bitmap
= NULL
;
2880 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2882 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2884 new_score
= (face
->Italic
^ it
) + (face
->Bold
^ bd
);
2885 if(!best
|| new_score
<= score
)
2887 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2888 face
->Italic
, face
->Bold
, it
, bd
);
2891 if(best
->scalable
&& score
== 0) break;
2895 newdiff
= height
- (signed int)(best
->size
.height
);
2897 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
2898 if(!best_bitmap
|| new_score
< score
||
2899 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
2901 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
2904 if(score
== 0 && diff
== 0) break;
2911 face
= best
->scalable
? best
: best_bitmap
;
2912 ret
->fake_italic
= (it
&& !face
->Italic
);
2913 ret
->fake_bold
= (bd
&& !face
->Bold
);
2915 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
2917 if(csi
.fs
.fsCsb
[0]) {
2918 ret
->charset
= lf
.lfCharSet
;
2919 ret
->codepage
= csi
.ciACP
;
2922 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
2924 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family
->FamilyName
),
2925 debugstr_w(face
->StyleName
), face
->file
, face
->face_index
);
2927 if(!face
->scalable
) {
2928 width
= face
->size
.x_ppem
>> 6;
2929 height
= face
->size
.y_ppem
>> 6;
2931 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
, width
, height
);
2939 if (ret
->charset
== SYMBOL_CHARSET
&&
2940 !pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
2943 else if (!pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
2947 pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
2950 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
2951 ret
->name
= strdupW(family
->FamilyName
);
2952 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
2953 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
2954 create_child_font_list(ret
);
2956 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
2958 ret
->aveWidth
= FT_IS_SCALABLE(ret
->ft_face
) ? abs(lf
.lfWidth
) : 0;
2959 list_add_head(&gdi_font_list
, &ret
->entry
);
2963 static void dump_gdi_font_list(void)
2966 struct list
*elem_ptr
;
2968 TRACE("---------- gdiFont Cache ----------\n");
2969 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
2970 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2971 TRACE("gdiFont=%p %s %d\n",
2972 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2975 TRACE("---------- Unused gdiFont Cache ----------\n");
2976 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
2977 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2978 TRACE("gdiFont=%p %s %d\n",
2979 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2983 /*************************************************************
2984 * WineEngDestroyFontInstance
2986 * free the gdiFont associated with this handle
2989 BOOL
WineEngDestroyFontInstance(HFONT handle
)
2994 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2997 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
2999 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3000 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3001 if(hflist
->hfont
== handle
)
3003 TRACE("removing child font %p from child list\n", gdiFont
);
3004 list_remove(&gdiFont
->entry
);
3009 TRACE("destroying hfont=%p\n", handle
);
3011 dump_gdi_font_list();
3013 font_elem_ptr
= list_head(&gdi_font_list
);
3014 while(font_elem_ptr
) {
3015 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3016 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3018 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3019 while(hfontlist_elem_ptr
) {
3020 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3021 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3022 if(hflist
->hfont
== handle
) {
3023 list_remove(&hflist
->entry
);
3024 HeapFree(GetProcessHeap(), 0, hflist
);
3028 if(list_empty(&gdiFont
->hfontlist
)) {
3029 TRACE("Moving to Unused list\n");
3030 list_remove(&gdiFont
->entry
);
3031 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3036 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3037 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3038 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3039 while(font_elem_ptr
) {
3040 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3041 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3042 TRACE("freeing %p\n", gdiFont
);
3043 list_remove(&gdiFont
->entry
);
3049 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3050 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3052 OUTLINETEXTMETRICW
*potm
= NULL
;
3054 TEXTMETRICW tm
, *ptm
;
3055 GdiFont
*font
= alloc_font();
3058 if(face
->scalable
) {
3062 height
= face
->size
.y_ppem
>> 6;
3063 width
= face
->size
.x_ppem
>> 6;
3066 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, width
, height
)))
3072 font
->name
= strdupW(face
->family
->FamilyName
);
3074 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
3076 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
3078 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3079 WineEngGetOutlineTextMetrics(font
, size
, potm
);
3080 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
3082 WineEngGetTextMetrics(font
, &tm
);
3086 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
3087 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
3088 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
3089 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
3090 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
3091 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
3092 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
3093 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
3094 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
3095 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
3096 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
3097 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
3098 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
3099 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
3100 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
3101 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
3102 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
3103 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
3104 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
3105 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
3106 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
3107 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3108 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3109 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3111 *ptype
= ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
3112 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
3113 *ptype
|= RASTER_FONTTYPE
;
3115 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
3116 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
3117 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
3119 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3120 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3121 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
3124 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
3126 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3127 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
3129 lstrcpynW(pelf
->elfFullName
,
3130 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
3132 lstrcpynW(pelf
->elfStyle
,
3133 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
3136 HeapFree(GetProcessHeap(), 0, potm
);
3138 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3140 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3141 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
3142 pelf
->elfStyle
[0] = '\0';
3145 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3150 /*************************************************************
3154 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3158 struct list
*family_elem_ptr
, *face_elem_ptr
;
3160 NEWTEXTMETRICEXW ntm
;
3161 DWORD type
, ret
= 1;
3167 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3169 if(plf
->lfFaceName
[0]) {
3171 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3174 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3175 debugstr_w(psub
->to
.name
));
3176 memcpy(&lf
, plf
, sizeof(lf
));
3177 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3181 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3182 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3183 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3184 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3185 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3186 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3187 for(i
= 0; i
< 32; i
++) {
3188 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3189 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3190 strcpyW(elf
.elfScript
, OEM_DOSW
);
3191 i
= 32; /* break out of loop */
3192 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3195 fs
.fsCsb
[0] = 1L << i
;
3197 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3199 csi
.ciCharset
= DEFAULT_CHARSET
;
3200 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3201 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3202 elf
.elfLogFont
.lfCharSet
=
3203 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3205 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3207 FIXME("Unknown elfscript for bit %d\n", i
);
3210 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3211 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3212 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3213 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3214 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3215 ntm
.ntmTm
.ntmFlags
);
3216 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3223 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3224 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3225 face_elem_ptr
= list_head(&family
->faces
);
3226 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3227 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3228 for(i
= 0; i
< 32; i
++) {
3229 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3230 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3231 strcpyW(elf
.elfScript
, OEM_DOSW
);
3232 i
= 32; /* break out of loop */
3233 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3236 fs
.fsCsb
[0] = 1L << i
;
3238 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3240 csi
.ciCharset
= DEFAULT_CHARSET
;
3241 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3242 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3243 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3246 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3248 FIXME("Unknown elfscript for bit %d\n", i
);
3251 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3252 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3253 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3254 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3255 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3256 ntm
.ntmTm
.ntmFlags
);
3257 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3266 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3268 pt
->x
.value
= vec
->x
>> 6;
3269 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3270 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3271 pt
->y
.value
= vec
->y
>> 6;
3272 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3273 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3277 /***************************************************
3278 * According to the MSDN documentation on WideCharToMultiByte,
3279 * certain codepages cannot set the default_used parameter.
3280 * This returns TRUE if the codepage can set that parameter, false else
3281 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3283 static BOOL
codepage_sets_default_used(UINT codepage
)
3296 static FT_UInt
get_glyph_index(GdiFont
*font
, UINT glyph
)
3298 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
3299 WCHAR wc
= (WCHAR
)glyph
;
3301 BOOL
*default_used_pointer
;
3304 default_used_pointer
= NULL
;
3305 default_used
= FALSE
;
3306 if (codepage_sets_default_used(font
->codepage
))
3307 default_used_pointer
= &default_used
;
3308 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
3311 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
3312 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
3316 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
3317 glyph
= glyph
+ 0xf000;
3318 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
3321 /*************************************************************
3322 * WineEngGetGlyphIndices
3324 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3326 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
3327 LPWORD pgi
, DWORD flags
)
3330 WCHAR default_char
= 0;
3333 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0x001f; /* Indicate non existence */
3335 for(i
= 0; i
< count
; i
++)
3337 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
3342 WineEngGetTextMetrics(font
, &textm
);
3343 default_char
= textm
.tmDefaultChar
;
3345 pgi
[i
] = default_char
;
3351 /*************************************************************
3352 * WineEngGetGlyphOutline
3354 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3355 * except that the first parameter is the HWINEENGFONT of the font in
3356 * question rather than an HDC.
3359 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
3360 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3363 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
3364 FT_Face ft_face
= incoming_font
->ft_face
;
3365 GdiFont
*font
= incoming_font
;
3366 FT_UInt glyph_index
;
3367 DWORD width
, height
, pitch
, needed
= 0;
3368 FT_Bitmap ft_bitmap
;
3370 INT left
, right
, top
= 0, bottom
= 0;
3372 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3373 float widthRatio
= 1.0;
3374 FT_Matrix transMat
= identityMat
;
3375 BOOL needsTransform
= FALSE
;
3378 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
3379 buflen
, buf
, lpmat
);
3381 if(format
& GGO_GLYPH_INDEX
) {
3382 glyph_index
= glyph
;
3383 format
&= ~GGO_GLYPH_INDEX
;
3385 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
3386 ft_face
= font
->ft_face
;
3389 if(glyph_index
>= font
->gmsize
) {
3390 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
3391 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
3392 font
->gmsize
* sizeof(*font
->gm
));
3394 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
3395 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
3396 return 1; /* FIXME */
3400 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
3401 load_flags
|= FT_LOAD_NO_BITMAP
;
3403 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
3406 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
3410 /* Scaling factor */
3411 if (font
->aveWidth
&& font
->potm
) {
3412 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
3415 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
3416 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
3418 font
->gm
[glyph_index
].adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
3419 font
->gm
[glyph_index
].lsb
= left
>> 6;
3420 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
3422 /* Scaling transform */
3423 if(font
->aveWidth
) {
3425 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
3428 scaleMat
.yy
= (1 << 16);
3430 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
3431 needsTransform
= TRUE
;
3434 /* Slant transform */
3435 if (font
->fake_italic
) {
3438 slantMat
.xx
= (1 << 16);
3439 slantMat
.xy
= ((1 << 16) >> 2);
3441 slantMat
.yy
= (1 << 16);
3442 pFT_Matrix_Multiply(&slantMat
, &transMat
);
3443 needsTransform
= TRUE
;
3446 /* Rotation transform */
3447 if(font
->orientation
) {
3448 FT_Matrix rotationMat
;
3450 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
3451 pFT_Vector_Unit(&vecAngle
, angle
);
3452 rotationMat
.xx
= vecAngle
.x
;
3453 rotationMat
.xy
= -vecAngle
.y
;
3454 rotationMat
.yx
= -rotationMat
.xy
;
3455 rotationMat
.yy
= rotationMat
.xx
;
3457 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
3458 needsTransform
= TRUE
;
3461 /* Extra transformation specified by caller */
3464 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
3465 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
3466 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
3467 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
3468 pFT_Matrix_Multiply(&extraMat
, &transMat
);
3469 needsTransform
= TRUE
;
3472 if(!needsTransform
) {
3473 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
3474 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
3475 ft_face
->glyph
->metrics
.height
) & -64;
3476 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
3477 lpgm
->gmCellIncY
= 0;
3481 for(xc
= 0; xc
< 2; xc
++) {
3482 for(yc
= 0; yc
< 2; yc
++) {
3483 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
3484 xc
* ft_face
->glyph
->metrics
.width
);
3485 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
3486 yc
* ft_face
->glyph
->metrics
.height
;
3487 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
3488 pFT_Vector_Transform(&vec
, &transMat
);
3489 if(xc
== 0 && yc
== 0) {
3490 left
= right
= vec
.x
;
3491 top
= bottom
= vec
.y
;
3493 if(vec
.x
< left
) left
= vec
.x
;
3494 else if(vec
.x
> right
) right
= vec
.x
;
3495 if(vec
.y
< bottom
) bottom
= vec
.y
;
3496 else if(vec
.y
> top
) top
= vec
.y
;
3501 right
= (right
+ 63) & -64;
3502 bottom
= bottom
& -64;
3503 top
= (top
+ 63) & -64;
3505 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
3506 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
3508 pFT_Vector_Transform(&vec
, &transMat
);
3509 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
3510 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
3512 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
3513 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
3514 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
3515 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
3517 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
3518 font
->gm
[glyph_index
].init
= TRUE
;
3520 if(format
== GGO_METRICS
)
3521 return 1; /* FIXME */
3523 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
3524 TRACE("loaded a bitmap\n");
3530 width
= lpgm
->gmBlackBoxX
;
3531 height
= lpgm
->gmBlackBoxY
;
3532 pitch
= ((width
+ 31) >> 5) << 2;
3533 needed
= pitch
* height
;
3535 if(!buf
|| !buflen
) break;
3537 switch(ft_face
->glyph
->format
) {
3538 case ft_glyph_format_bitmap
:
3540 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3541 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
3542 INT h
= ft_face
->glyph
->bitmap
.rows
;
3544 memcpy(dst
, src
, w
);
3545 src
+= ft_face
->glyph
->bitmap
.pitch
;
3551 case ft_glyph_format_outline
:
3552 ft_bitmap
.width
= width
;
3553 ft_bitmap
.rows
= height
;
3554 ft_bitmap
.pitch
= pitch
;
3555 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
3556 ft_bitmap
.buffer
= buf
;
3558 if(needsTransform
) {
3559 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3562 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3564 /* Note: FreeType will only set 'black' bits for us. */
3565 memset(buf
, 0, needed
);
3566 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3570 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3575 case GGO_GRAY2_BITMAP
:
3576 case GGO_GRAY4_BITMAP
:
3577 case GGO_GRAY8_BITMAP
:
3578 case WINE_GGO_GRAY16_BITMAP
:
3580 unsigned int mult
, row
, col
;
3583 width
= lpgm
->gmBlackBoxX
;
3584 height
= lpgm
->gmBlackBoxY
;
3585 pitch
= (width
+ 3) / 4 * 4;
3586 needed
= pitch
* height
;
3588 if(!buf
|| !buflen
) break;
3589 ft_bitmap
.width
= width
;
3590 ft_bitmap
.rows
= height
;
3591 ft_bitmap
.pitch
= pitch
;
3592 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
3593 ft_bitmap
.buffer
= buf
;
3595 if(needsTransform
) {
3596 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3599 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3601 memset(ft_bitmap
.buffer
, 0, buflen
);
3603 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3605 if(format
== GGO_GRAY2_BITMAP
)
3607 else if(format
== GGO_GRAY4_BITMAP
)
3609 else if(format
== GGO_GRAY8_BITMAP
)
3611 else if(format
== WINE_GGO_GRAY16_BITMAP
)
3619 for(row
= 0; row
< height
; row
++) {
3621 for(col
= 0; col
< width
; col
++, ptr
++) {
3622 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
3631 int contour
, point
= 0, first_pt
;
3632 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3633 TTPOLYGONHEADER
*pph
;
3635 DWORD pph_start
, cpfx
, type
;
3637 if(buflen
== 0) buf
= NULL
;
3639 if (needsTransform
&& buf
) {
3640 pFT_Outline_Transform(outline
, &transMat
);
3643 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3645 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3648 pph
->dwType
= TT_POLYGON_TYPE
;
3649 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3651 needed
+= sizeof(*pph
);
3653 while(point
<= outline
->contours
[contour
]) {
3654 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3655 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3656 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3660 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3663 } while(point
<= outline
->contours
[contour
] &&
3664 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3665 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3666 /* At the end of a contour Windows adds the start point, but
3668 if(point
> outline
->contours
[contour
] &&
3669 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3671 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3673 } else if(point
<= outline
->contours
[contour
] &&
3674 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3675 /* add closing pt for bezier */
3677 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3685 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3688 pph
->cb
= needed
- pph_start
;
3694 /* Convert the quadratic Beziers to cubic Beziers.
3695 The parametric eqn for a cubic Bezier is, from PLRM:
3696 r(t) = at^3 + bt^2 + ct + r0
3697 with the control points:
3702 A quadratic Beizer has the form:
3703 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3705 So equating powers of t leads to:
3706 r1 = 2/3 p1 + 1/3 p0
3707 r2 = 2/3 p1 + 1/3 p2
3708 and of course r0 = p0, r3 = p2
3711 int contour
, point
= 0, first_pt
;
3712 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3713 TTPOLYGONHEADER
*pph
;
3715 DWORD pph_start
, cpfx
, type
;
3716 FT_Vector cubic_control
[4];
3717 if(buflen
== 0) buf
= NULL
;
3719 if (needsTransform
&& buf
) {
3720 pFT_Outline_Transform(outline
, &transMat
);
3723 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3725 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3728 pph
->dwType
= TT_POLYGON_TYPE
;
3729 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3731 needed
+= sizeof(*pph
);
3733 while(point
<= outline
->contours
[contour
]) {
3734 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3735 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3736 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3739 if(type
== TT_PRIM_LINE
) {
3741 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3745 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3748 /* FIXME: Possible optimization in endpoint calculation
3749 if there are two consecutive curves */
3750 cubic_control
[0] = outline
->points
[point
-1];
3751 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3752 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3753 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3754 cubic_control
[0].x
>>= 1;
3755 cubic_control
[0].y
>>= 1;
3757 if(point
+1 > outline
->contours
[contour
])
3758 cubic_control
[3] = outline
->points
[first_pt
];
3760 cubic_control
[3] = outline
->points
[point
+1];
3761 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
3762 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3763 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3764 cubic_control
[3].x
>>= 1;
3765 cubic_control
[3].y
>>= 1;
3768 /* r1 = 1/3 p0 + 2/3 p1
3769 r2 = 1/3 p2 + 2/3 p1 */
3770 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3771 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3772 cubic_control
[2] = cubic_control
[1];
3773 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3774 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3775 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3776 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3778 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3779 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3780 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3785 } while(point
<= outline
->contours
[contour
] &&
3786 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3787 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3788 /* At the end of a contour Windows adds the start point,
3789 but only for Beziers and we've already done that.
3791 if(point
<= outline
->contours
[contour
] &&
3792 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3793 /* This is the closing pt of a bezier, but we've already
3794 added it, so just inc point and carry on */
3801 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3804 pph
->cb
= needed
- pph_start
;
3810 FIXME("Unsupported format %d\n", format
);
3816 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
3818 FT_Face ft_face
= font
->ft_face
;
3819 #ifdef HAVE_FREETYPE_FTWINFNT_H
3820 FT_WinFNT_HeaderRec winfnt_header
;
3822 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
3823 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3824 font
->potm
->otmSize
= size
;
3826 #define TM font->potm->otmTextMetrics
3827 #ifdef HAVE_FREETYPE_FTWINFNT_H
3828 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3830 TM
.tmHeight
= winfnt_header
.pixel_height
;
3831 TM
.tmAscent
= winfnt_header
.ascent
;
3832 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3833 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3834 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3835 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3836 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3837 TM
.tmWeight
= winfnt_header
.weight
;
3839 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3840 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3841 TM
.tmFirstChar
= winfnt_header
.first_char
;
3842 TM
.tmLastChar
= winfnt_header
.last_char
;
3843 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3844 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3845 TM
.tmItalic
= winfnt_header
.italic
;
3846 TM
.tmUnderlined
= font
->underline
;
3847 TM
.tmStruckOut
= font
->strikeout
;
3848 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3849 TM
.tmCharSet
= winfnt_header
.charset
;
3854 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3855 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3856 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3857 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3858 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3859 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3860 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3861 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3863 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3864 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3866 TM
.tmLastChar
= 255;
3867 TM
.tmDefaultChar
= 32;
3868 TM
.tmBreakChar
= 32;
3869 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3870 TM
.tmUnderlined
= font
->underline
;
3871 TM
.tmStruckOut
= font
->strikeout
;
3872 /* NB inverted meaning of TMPF_FIXED_PITCH */
3873 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
3874 TM
.tmCharSet
= font
->charset
;
3881 /*************************************************************
3882 * WineEngGetTextMetrics
3885 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
3888 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3889 if(!get_bitmap_text_metrics(font
))
3892 if(!font
->potm
) return FALSE
;
3893 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
3895 if (font
->aveWidth
) {
3896 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
3902 /*************************************************************
3903 * WineEngGetOutlineTextMetrics
3906 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
3907 OUTLINETEXTMETRICW
*potm
)
3909 FT_Face ft_face
= font
->ft_face
;
3910 UINT needed
, lenfam
, lensty
, ret
;
3912 TT_HoriHeader
*pHori
;
3913 TT_Postscript
*pPost
;
3914 FT_Fixed x_scale
, y_scale
;
3915 WCHAR
*family_nameW
, *style_nameW
;
3916 static const WCHAR spaceW
[] = {' ', '\0'};
3918 INT ascent
, descent
;
3920 TRACE("font=%p\n", font
);
3922 if(!FT_IS_SCALABLE(ft_face
))
3926 if(cbSize
>= font
->potm
->otmSize
)
3927 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
3928 return font
->potm
->otmSize
;
3932 needed
= sizeof(*potm
);
3934 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
3935 family_nameW
= strdupW(font
->name
);
3937 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
3939 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
3940 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
3941 style_nameW
, lensty
/sizeof(WCHAR
));
3943 /* These names should be read from the TT name table */
3945 /* length of otmpFamilyName */
3948 /* length of otmpFaceName */
3949 if(!strcasecmp(ft_face
->style_name
, "regular")) {
3950 needed
+= lenfam
; /* just the family name */
3952 needed
+= lenfam
+ lensty
; /* family + " " + style */
3955 /* length of otmpStyleName */
3958 /* length of otmpFullName */
3959 needed
+= lenfam
+ lensty
;
3962 x_scale
= ft_face
->size
->metrics
.x_scale
;
3963 y_scale
= ft_face
->size
->metrics
.y_scale
;
3965 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3967 FIXME("Can't find OS/2 table - not TT font?\n");
3972 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3974 FIXME("Can't find HHEA table - not TT font?\n");
3979 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3981 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",
3982 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3983 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3984 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3985 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3986 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3988 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
3989 font
->potm
->otmSize
= needed
;
3991 #define TM font->potm->otmTextMetrics
3993 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
3994 ascent
= pHori
->Ascender
;
3995 descent
= -pHori
->Descender
;
3997 ascent
= pOS2
->usWinAscent
;
3998 descent
= pOS2
->usWinDescent
;
4002 TM
.tmAscent
= font
->yMax
;
4003 TM
.tmDescent
= -font
->yMin
;
4004 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4006 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4007 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4008 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4009 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4012 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4015 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4017 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4018 ((ascent
+ descent
) -
4019 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4021 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4022 if (TM
.tmAveCharWidth
== 0) {
4023 TM
.tmAveCharWidth
= 1;
4025 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4026 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4028 TM
.tmDigitizedAspectX
= 300;
4029 TM
.tmDigitizedAspectY
= 300;
4030 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4031 * symbol range to 0 - f0ff
4033 if (font
->charset
== SYMBOL_CHARSET
)
4036 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4037 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4038 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4039 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4040 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4041 TM
.tmUnderlined
= font
->underline
;
4042 TM
.tmStruckOut
= font
->strikeout
;
4044 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4045 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4046 (pOS2
->version
== 0xFFFFU
||
4047 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4048 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4050 TM
.tmPitchAndFamily
= 0;
4052 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4053 case PAN_FAMILY_SCRIPT
:
4054 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4056 case PAN_FAMILY_DECORATIVE
:
4057 case PAN_FAMILY_PICTORIAL
:
4058 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4060 case PAN_FAMILY_TEXT_DISPLAY
:
4061 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4062 TM
.tmPitchAndFamily
= FF_MODERN
;
4064 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4065 case PAN_SERIF_NORMAL_SANS
:
4066 case PAN_SERIF_OBTUSE_SANS
:
4067 case PAN_SERIF_PERP_SANS
:
4068 TM
.tmPitchAndFamily
|= FF_SWISS
;
4071 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4076 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4079 if(FT_IS_SCALABLE(ft_face
))
4080 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4081 if(FT_IS_SFNT(ft_face
))
4082 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4084 TM
.tmCharSet
= font
->charset
;
4087 font
->potm
->otmFiller
= 0;
4088 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4089 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4090 font
->potm
->otmfsType
= pOS2
->fsType
;
4091 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4092 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4093 font
->potm
->otmItalicAngle
= 0; /* POST table */
4094 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4095 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4096 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4097 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4098 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4099 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
4100 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4101 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
4102 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
4103 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
4104 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
4105 font
->potm
->otmMacDescent
= 0;
4106 font
->potm
->otmMacLineGap
= 0;
4107 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
4108 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
4109 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
4110 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
4111 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
4112 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
4113 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
4114 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
4115 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
4116 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
4117 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
4119 font
->potm
->otmsUnderscoreSize
= 0;
4120 font
->potm
->otmsUnderscorePosition
= 0;
4122 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
4123 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
4126 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4127 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
4128 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
4129 strcpyW((WCHAR
*)cp
, family_nameW
);
4131 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
4132 strcpyW((WCHAR
*)cp
, style_nameW
);
4134 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
4135 strcpyW((WCHAR
*)cp
, family_nameW
);
4136 if(strcasecmp(ft_face
->style_name
, "regular")) {
4137 strcatW((WCHAR
*)cp
, spaceW
);
4138 strcatW((WCHAR
*)cp
, style_nameW
);
4139 cp
+= lenfam
+ lensty
;
4142 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
4143 strcpyW((WCHAR
*)cp
, family_nameW
);
4144 strcatW((WCHAR
*)cp
, spaceW
);
4145 strcatW((WCHAR
*)cp
, style_nameW
);
4148 if(potm
&& needed
<= cbSize
)
4149 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4152 HeapFree(GetProcessHeap(), 0, style_nameW
);
4153 HeapFree(GetProcessHeap(), 0, family_nameW
);
4158 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
4160 HFONTLIST
*hfontlist
;
4161 child
->font
= alloc_font();
4162 child
->font
->ft_face
= OpenFontFile(child
->font
, child
->file_name
, child
->index
, 0, -font
->ppem
);
4163 if(!child
->font
->ft_face
)
4165 free_font(child
->font
);
4170 child
->font
->orientation
= font
->orientation
;
4171 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
4172 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
4173 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
4174 child
->font
->base_font
= font
;
4175 list_add_head(&child_font_list
, &child
->font
->entry
);
4176 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
4180 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
4183 CHILD_FONT
*child_font
;
4186 font
= font
->base_font
;
4188 *linked_font
= font
;
4190 if((*glyph
= get_glyph_index(font
, c
)))
4193 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
4195 if(!child_font
->font
)
4196 if(!load_child_font(font
, child_font
))
4199 if(!child_font
->font
->ft_face
)
4201 g
= get_glyph_index(child_font
->font
, c
);
4205 *linked_font
= child_font
->font
;
4212 /*************************************************************
4213 * WineEngGetCharWidth
4216 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4221 FT_UInt glyph_index
;
4222 GdiFont
*linked_font
;
4224 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4226 for(c
= firstChar
; c
<= lastChar
; c
++) {
4227 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4228 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4229 &gm
, 0, NULL
, NULL
);
4230 buffer
[c
- firstChar
] = linked_font
->gm
[glyph_index
].adv
;
4235 /*************************************************************
4236 * WineEngGetCharABCWidths
4239 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4244 FT_UInt glyph_index
;
4245 GdiFont
*linked_font
;
4247 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4249 if(!FT_IS_SCALABLE(font
->ft_face
))
4252 for(c
= firstChar
; c
<= lastChar
; c
++) {
4253 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4254 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4255 &gm
, 0, NULL
, NULL
);
4256 buffer
[c
- firstChar
].abcA
= linked_font
->gm
[glyph_index
].lsb
;
4257 buffer
[c
- firstChar
].abcB
= linked_font
->gm
[glyph_index
].bbx
;
4258 buffer
[c
- firstChar
].abcC
= linked_font
->gm
[glyph_index
].adv
- linked_font
->gm
[glyph_index
].lsb
-
4259 linked_font
->gm
[glyph_index
].bbx
;
4264 /*************************************************************
4265 * WineEngGetCharABCWidthsI
4268 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4273 FT_UInt glyph_index
;
4274 GdiFont
*linked_font
;
4276 if(!FT_IS_SCALABLE(font
->ft_face
))
4279 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
4281 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
4282 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4283 &gm
, 0, NULL
, NULL
);
4284 buffer
[c
- firstChar
].abcA
= linked_font
->gm
[c
].lsb
;
4285 buffer
[c
- firstChar
].abcB
= linked_font
->gm
[c
].bbx
;
4286 buffer
[c
- firstChar
].abcC
= linked_font
->gm
[c
].adv
- linked_font
->gm
[c
].lsb
4287 - linked_font
->gm
[c
].bbx
;
4290 for(c
= 0; c
< count
; c
++) {
4291 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4292 &gm
, 0, NULL
, NULL
);
4293 buffer
[c
].abcA
= linked_font
->gm
[pgi
[c
]].lsb
;
4294 buffer
[c
].abcB
= linked_font
->gm
[pgi
[c
]].bbx
;
4295 buffer
[c
].abcC
= linked_font
->gm
[pgi
[c
]].adv
4296 - linked_font
->gm
[pgi
[c
]].lsb
- linked_font
->gm
[pgi
[c
]].bbx
;
4302 /*************************************************************
4303 * WineEngGetTextExtentExPoint
4306 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4307 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4313 FT_UInt glyph_index
;
4314 GdiFont
*linked_font
;
4316 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
4320 WineEngGetTextMetrics(font
, &tm
);
4321 size
->cy
= tm
.tmHeight
;
4323 for(idx
= 0; idx
< count
; idx
++) {
4324 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
4325 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4326 &gm
, 0, NULL
, NULL
);
4327 size
->cx
+= linked_font
->gm
[glyph_index
].adv
;
4329 if (! pnfit
|| ext
<= max_ext
) {
4339 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4343 /*************************************************************
4344 * WineEngGetTextExtentPointI
4347 BOOL
WineEngGetTextExtentPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4354 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
4357 WineEngGetTextMetrics(font
, &tm
);
4358 size
->cy
= tm
.tmHeight
;
4360 for(idx
= 0; idx
< count
; idx
++) {
4361 WineEngGetGlyphOutline(font
, indices
[idx
],
4362 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
4364 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
4366 TRACE("return %d,%d\n", size
->cx
, size
->cy
);
4370 /*************************************************************
4371 * WineEngGetFontData
4374 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4377 FT_Face ft_face
= font
->ft_face
;
4381 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
4382 font
, table
, offset
, buf
, cbData
);
4384 if(!FT_IS_SFNT(ft_face
))
4392 if(table
) { /* MS tags differ in endidness from FT ones */
4393 table
= table
>> 24 | table
<< 24 |
4394 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
4397 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4398 if(pFT_Load_Sfnt_Table
) {
4399 /* make sure value of len is the value freetype says it needs */
4401 FT_ULong needed
= 0;
4402 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4403 if( !err
&& needed
< len
) len
= needed
;
4405 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4407 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4408 else { /* Do it the hard way */
4409 TT_Face tt_face
= (TT_Face
) ft_face
;
4410 SFNT_Interface
*sfnt
;
4411 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
4414 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
4418 /* A field was added in the middle of the structure in 2.1.x */
4419 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
4421 /* make sure value of len is the value freetype says it needs */
4423 FT_ULong needed
= 0;
4424 err
= sfnt
->load_any(tt_face
, table
, offset
, NULL
, &needed
);
4425 if( !err
&& needed
< len
) len
= needed
;
4427 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
4433 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4434 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4435 "Please upgrade your freetype library.\n");
4438 err
= FT_Err_Unimplemented_Feature
;
4442 TRACE("Can't find table %08x.\n", table
);
4448 /*************************************************************
4449 * WineEngGetTextFace
4452 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4455 lstrcpynW(str
, font
->name
, count
);
4456 return strlenW(font
->name
);
4458 return strlenW(font
->name
) + 1;
4461 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4463 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
4464 return font
->charset
;
4467 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4469 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
4470 struct list
*first_hfont
;
4473 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
4474 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
4475 if(font
== linked_font
)
4476 *new_hfont
= dc
->hFont
;
4479 first_hfont
= list_head(&linked_font
->hfontlist
);
4480 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
4486 /* Retrieve a list of supported Unicode ranges for a given font.
4487 * Can be called with NULL gs to calculate the buffer size. Returns
4488 * the number of ranges found.
4490 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
4492 DWORD num_ranges
= 0;
4494 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4497 FT_ULong char_code
, char_code_prev
;
4500 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
4502 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4503 face
->num_glyphs
, glyph_code
, char_code
);
4505 if (!glyph_code
) return 0;
4509 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4510 gs
->ranges
[0].cGlyphs
= 0;
4511 gs
->cGlyphsSupported
= 0;
4517 if (char_code
< char_code_prev
)
4519 ERR("expected increasing char code from FT_Get_Next_Char\n");
4522 if (char_code
- char_code_prev
> 1)
4527 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4528 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4529 gs
->cGlyphsSupported
++;
4534 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4535 gs
->cGlyphsSupported
++;
4537 char_code_prev
= char_code
;
4538 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
4542 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
4547 DWORD
WineEngGetFontUnicodeRanges(HDC hdc
, LPGLYPHSET glyphset
)
4550 DC
*dc
= DC_GetDCPtr(hdc
);
4552 TRACE("(%p, %p)\n", hdc
, glyphset
);
4558 DWORD num_ranges
= get_font_unicode_ranges(dc
->gdiFont
->ft_face
, glyphset
);
4560 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
4563 glyphset
->cbThis
= size
;
4564 glyphset
->cRanges
= num_ranges
;
4568 GDI_ReleaseObj(hdc
);
4572 /*************************************************************
4575 BOOL WINAPI
FontIsLinked(HDC hdc
)
4577 DC
*dc
= DC_GetDCPtr(hdc
);
4580 if(!dc
) return FALSE
;
4581 if(dc
->gdiFont
&& !list_empty(&dc
->gdiFont
->child_fonts
))
4583 GDI_ReleaseObj(hdc
);
4584 TRACE("returning %d\n", ret
);
4588 static BOOL
is_hinting_enabled(void)
4590 /* Use the >= 2.2.0 function if available */
4591 if(pFT_Get_TrueType_Engine_Type
)
4593 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
4594 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
4596 #ifdef FT_DRIVER_HAS_HINTER
4601 /* otherwise if we've been compiled with < 2.2.0 headers
4602 use the internal macro */
4603 mod
= pFT_Get_Module(library
, "truetype");
4604 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
4612 /*************************************************************************
4613 * GetRasterizerCaps (GDI32.@)
4615 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
4617 static int hinting
= -1;
4621 hinting
= is_hinting_enabled();
4622 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
4625 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
4626 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
4627 lprs
->nLanguageID
= 0;
4631 /*************************************************************************
4632 * Kerning support for TrueType fonts
4634 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4636 struct TT_kern_table
4642 struct TT_kern_subtable
4651 USHORT horizontal
: 1;
4653 USHORT cross_stream
: 1;
4654 USHORT override
: 1;
4655 USHORT reserved1
: 4;
4661 struct TT_format0_kern_subtable
4665 USHORT entrySelector
;
4676 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
4677 const struct TT_format0_kern_subtable
*tt_f0_ks
,
4678 const USHORT
*glyph_to_char
,
4679 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
4682 const struct TT_kern_pair
*tt_kern_pair
;
4684 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
4686 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
4688 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4689 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
4690 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
4692 if (!kern_pair
|| !cPairs
)
4695 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
4697 nPairs
= min(nPairs
, cPairs
);
4699 for (i
= 0; i
< nPairs
; i
++)
4701 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
4702 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
4703 /* this algorithm appears to better match what Windows does */
4704 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
4705 if (kern_pair
->iKernAmount
< 0)
4707 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
4708 kern_pair
->iKernAmount
-= font
->ppem
;
4710 else if (kern_pair
->iKernAmount
> 0)
4712 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
4713 kern_pair
->iKernAmount
+= font
->ppem
;
4715 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
4717 TRACE("left %u right %u value %d\n",
4718 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
4722 TRACE("copied %u entries\n", nPairs
);
4726 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
4730 const struct TT_kern_table
*tt_kern_table
;
4731 const struct TT_kern_subtable
*tt_kern_subtable
;
4733 USHORT
*glyph_to_char
;
4735 if (font
->total_kern_pairs
!= (DWORD
)-1)
4737 if (cPairs
&& kern_pair
)
4739 cPairs
= min(cPairs
, font
->total_kern_pairs
);
4740 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
4743 return font
->total_kern_pairs
;
4746 font
->total_kern_pairs
= 0;
4748 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
4750 if (length
== GDI_ERROR
)
4752 TRACE("no kerning data in the font\n");
4756 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
4759 WARN("Out of memory\n");
4763 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
4765 /* build a glyph index to char code map */
4766 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
4769 WARN("Out of memory allocating a glyph index to char code map\n");
4770 HeapFree(GetProcessHeap(), 0, buf
);
4774 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4780 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
4782 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4783 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
4787 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4789 /* FIXME: This doesn't match what Windows does: it does some fancy
4790 * things with duplicate glyph index to char code mappings, while
4791 * we just avoid overriding existing entries.
4793 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
4794 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
4796 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
4803 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
4804 for (n
= 0; n
<= 65535; n
++)
4805 glyph_to_char
[n
] = (USHORT
)n
;
4808 tt_kern_table
= buf
;
4809 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
4810 TRACE("version %u, nTables %u\n",
4811 GET_BE_WORD(tt_kern_table
->version
), nTables
);
4813 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
4815 for (i
= 0; i
< nTables
; i
++)
4817 struct TT_kern_subtable tt_kern_subtable_copy
;
4819 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
4820 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
4821 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
4823 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4824 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
4825 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
4827 /* According to the TrueType specification this is the only format
4828 * that will be properly interpreted by Windows and OS/2
4830 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
4832 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
4834 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4835 glyph_to_char
, NULL
, 0);
4836 font
->total_kern_pairs
+= new_chunk
;
4838 if (!font
->kern_pairs
)
4839 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
4840 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
4842 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
4843 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
4845 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4846 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
4849 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
4851 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
4854 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
4855 HeapFree(GetProcessHeap(), 0, buf
);
4857 if (cPairs
&& kern_pair
)
4859 cPairs
= min(cPairs
, font
->total_kern_pairs
);
4860 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
4863 return font
->total_kern_pairs
;
4866 #else /* HAVE_FREETYPE */
4868 /*************************************************************************/
4870 BOOL
WineEngInit(void)
4874 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
4878 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
4883 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4888 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4889 LPWORD pgi
, DWORD flags
)
4894 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
4895 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4898 ERR("called but we don't have FreeType\n");
4902 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4904 ERR("called but we don't have FreeType\n");
4908 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4909 OUTLINETEXTMETRICW
*potm
)
4911 ERR("called but we don't have FreeType\n");
4915 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4918 ERR("called but we don't have FreeType\n");
4922 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4925 ERR("called but we don't have FreeType\n");
4929 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4932 ERR("called but we don't have FreeType\n");
4936 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4937 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
4939 ERR("called but we don't have FreeType\n");
4943 BOOL
WineEngGetTextExtentPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4946 ERR("called but we don't have FreeType\n");
4950 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4953 ERR("called but we don't have FreeType\n");
4957 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4959 ERR("called but we don't have FreeType\n");
4963 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
4969 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
4975 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4978 return DEFAULT_CHARSET
;
4981 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4986 DWORD
WineEngGetFontUnicodeRanges(HDC hdc
, LPGLYPHSET glyphset
)
4988 FIXME("(%p, %p): stub\n", hdc
, glyphset
);
4992 BOOL WINAPI
FontIsLinked(HDC hdc
)
4997 /*************************************************************************
4998 * GetRasterizerCaps (GDI32.@)
5000 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5002 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5004 lprs
->nLanguageID
= 0;
5008 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5010 ERR("called but we don't have FreeType\n");
5014 #endif /* HAVE_FREETYPE */