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 HAVE_FT_TRUETYPEENGINETYPE
134 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
135 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
136 FT_TRUETYPE_ENGINE_TYPE_PATENTED
137 } FT_TrueTypeEngineType
;
140 static FT_Library library
= 0;
147 static FT_Version_t FT_Version
;
148 static DWORD FT_SimpleVersion
;
150 static void *ft_handle
= NULL
;
152 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
153 MAKE_FUNCPTR(FT_Vector_Unit
);
154 MAKE_FUNCPTR(FT_Done_Face
);
155 MAKE_FUNCPTR(FT_Get_Char_Index
);
156 MAKE_FUNCPTR(FT_Get_Module
);
157 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
158 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
159 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
160 MAKE_FUNCPTR(FT_Init_FreeType
);
161 MAKE_FUNCPTR(FT_Load_Glyph
);
162 MAKE_FUNCPTR(FT_Matrix_Multiply
);
163 MAKE_FUNCPTR(FT_MulFix
);
164 MAKE_FUNCPTR(FT_New_Face
);
165 MAKE_FUNCPTR(FT_New_Memory_Face
);
166 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
167 MAKE_FUNCPTR(FT_Outline_Transform
);
168 MAKE_FUNCPTR(FT_Outline_Translate
);
169 MAKE_FUNCPTR(FT_Select_Charmap
);
170 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
171 MAKE_FUNCPTR(FT_Vector_Transform
);
172 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
173 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
174 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
175 static FT_ULong (*pFT_Get_Next_Char
)(FT_Face
,FT_ULong
,FT_UInt
*);
176 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
177 #ifdef HAVE_FREETYPE_FTWINFNT_H
178 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
181 #ifdef SONAME_LIBFONTCONFIG
182 #include <fontconfig/fontconfig.h>
183 MAKE_FUNCPTR(FcConfigGetCurrent
);
184 MAKE_FUNCPTR(FcFontList
);
185 MAKE_FUNCPTR(FcFontSetDestroy
);
186 MAKE_FUNCPTR(FcInit
);
187 MAKE_FUNCPTR(FcObjectSetAdd
);
188 MAKE_FUNCPTR(FcObjectSetCreate
);
189 MAKE_FUNCPTR(FcObjectSetDestroy
);
190 MAKE_FUNCPTR(FcPatternCreate
);
191 MAKE_FUNCPTR(FcPatternDestroy
);
192 MAKE_FUNCPTR(FcPatternGetBool
);
193 MAKE_FUNCPTR(FcPatternGetString
);
198 #ifndef ft_encoding_none
199 #define FT_ENCODING_NONE ft_encoding_none
201 #ifndef ft_encoding_ms_symbol
202 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
204 #ifndef ft_encoding_unicode
205 #define FT_ENCODING_UNICODE ft_encoding_unicode
207 #ifndef ft_encoding_apple_roman
208 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
211 #ifdef WORDS_BIGENDIAN
212 #define GET_BE_WORD(x) (x)
214 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
217 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
224 FT_Short internal_leading
;
227 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
228 So to let this compile on older versions of FreeType we'll define the
229 new structure here. */
231 FT_Short height
, width
;
232 FT_Pos size
, x_ppem
, y_ppem
;
235 typedef struct tagFace
{
243 FONTSIGNATURE fs_links
;
244 FT_Fixed font_version
;
246 Bitmap_Size size
; /* set if face is a bitmap */
247 BOOL external
; /* TRUE if we should manually add this font to the registry */
248 struct tagFamily
*family
;
251 typedef struct tagFamily
{
253 const WCHAR
*FamilyName
;
259 INT adv
; /* These three hold to widths of the unrotated chars */
277 typedef struct tagHFONTLIST
{
291 struct font_mapping
*mapping
;
302 struct list hfontlist
;
307 OUTLINETEXTMETRICW
*potm
;
308 DWORD total_kern_pairs
;
309 KERNINGPAIR
*kern_pairs
;
312 struct list child_fonts
;
318 const WCHAR
*font_name
;
322 #define GM_BLOCK_SIZE 128
323 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
325 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
326 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
327 #define UNUSED_CACHE_SIZE 10
328 static struct list child_font_list
= LIST_INIT(child_font_list
);
329 static struct list system_links
= LIST_INIT(system_links
);
331 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
333 static struct list font_list
= LIST_INIT(font_list
);
335 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
336 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
337 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
339 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
341 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
342 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
343 'W','i','n','d','o','w','s','\\',
344 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
345 'F','o','n','t','s','\0'};
347 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
348 'W','i','n','d','o','w','s',' ','N','T','\\',
349 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
350 'F','o','n','t','s','\0'};
352 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
353 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
354 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
355 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
357 static const WCHAR
* const SystemFontValues
[4] = {
364 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
365 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
367 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
368 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
369 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
370 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
371 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
372 'E','u','r','o','p','e','a','n','\0'};
373 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
374 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
375 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
376 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
377 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
378 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
379 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
380 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
381 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
382 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
383 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
384 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
386 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
396 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
404 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
413 typedef struct tagFontSubst
{
429 static struct list mappings_list
= LIST_INIT( mappings_list
);
431 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
433 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
435 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
437 /****************************************
438 * Notes on .fon files
440 * The fonts System, FixedSys and Terminal are special. There are typically multiple
441 * versions installed for different resolutions and codepages. Windows stores which one to use
442 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
444 * FIXEDFON.FON FixedSys
446 * OEMFONT.FON Terminal
447 * LogPixels Current dpi set by the display control panel applet
448 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
449 * also has a LogPixels value that appears to mirror this)
451 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
452 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
453 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
454 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
455 * so that makes sense.
457 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
458 * to be mapped into the registry on Windows 2000 at least).
461 * ega80woa.fon=ega80850.fon
462 * ega40woa.fon=ega40850.fon
463 * cga80woa.fon=cga80850.fon
464 * cga40woa.fon=cga40850.fon
467 #ifdef HAVE_CARBON_CARBON_H
468 static char *find_cache_dir(void)
472 static char cached_path
[MAX_PATH
];
473 static const char *wine
= "/Wine", *fonts
= "/Fonts";
475 if(*cached_path
) return cached_path
;
477 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
480 WARN("can't create cached data folder\n");
483 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
486 WARN("can't create cached data path\n");
490 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
492 ERR("Could not create full path\n");
496 strcat(cached_path
, wine
);
498 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
500 WARN("Couldn't mkdir %s\n", cached_path
);
504 strcat(cached_path
, fonts
);
505 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
507 WARN("Couldn't mkdir %s\n", cached_path
);
514 /******************************************************************
517 * Extracts individual TrueType font files from a Mac suitcase font
518 * and saves them into the user's caches directory (see
520 * Returns a NULL terminated array of filenames.
522 * We do this because they are apps that try to read ttf files
523 * themselves and they don't like Mac suitcase files.
525 static char **expand_mac_font(const char *path
)
532 const char *filename
;
536 unsigned int size
, max_size
;
539 TRACE("path %s\n", path
);
541 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
544 WARN("failed to get ref\n");
548 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
551 TRACE("no data fork, so trying resource fork\n");
552 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
555 TRACE("unable to open resource fork\n");
562 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
565 CloseResFile(res_ref
);
569 out_dir
= find_cache_dir();
571 filename
= strrchr(path
, '/');
572 if(!filename
) filename
= path
;
575 /* output filename has the form out_dir/filename_%04x.ttf */
576 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
583 unsigned short *num_faces_ptr
, num_faces
, face
;
586 ResType fond_res
= 0x464f4e44; /* 'FOND' */
588 fond
= Get1IndResource(fond_res
, idx
);
590 TRACE("got fond resource %d\n", idx
);
593 fam_rec
= *(FamRec
**)fond
;
594 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
595 num_faces
= GET_BE_WORD(*num_faces_ptr
);
597 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
598 TRACE("num faces %04x\n", num_faces
);
599 for(face
= 0; face
< num_faces
; face
++, assoc
++)
602 ResType sfnt_res
= 0x73666e74; /* 'sfnt' */
603 unsigned short size
, font_id
;
606 size
= GET_BE_WORD(assoc
->fontSize
);
607 font_id
= GET_BE_WORD(assoc
->fontID
);
610 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
614 TRACE("trying to load sfnt id %04x\n", font_id
);
615 sfnt
= GetResource(sfnt_res
, font_id
);
618 TRACE("can't get sfnt resource %04x\n", font_id
);
622 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
627 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
629 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
630 if(fd
!= -1 || errno
== EEXIST
)
634 unsigned char *sfnt_data
;
637 sfnt_data
= *(unsigned char**)sfnt
;
638 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
642 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
645 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
647 ret
.array
[ret
.size
++] = output
;
651 WARN("unable to create %s\n", output
);
652 HeapFree(GetProcessHeap(), 0, output
);
655 ReleaseResource(sfnt
);
658 ReleaseResource(fond
);
661 CloseResFile(res_ref
);
666 #endif /* HAVE_CARBON_CARBON_H */
668 static inline BOOL
is_win9x(void)
670 return GetVersion() & 0x80000000;
673 This function builds an FT_Fixed from a float. It puts the integer part
674 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
675 It fails if the integer part of the float number is greater than SHORT_MAX.
677 static inline FT_Fixed
FT_FixedFromFloat(float f
)
680 unsigned short fract
= (f
- value
) * 0xFFFF;
681 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
685 This function builds an FT_Fixed from a FIXED. It simply put f.value
686 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
688 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
690 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
694 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
699 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
700 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
702 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
703 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
705 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
707 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
709 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
711 file
= strrchr(face
->file
, '/');
716 if(!strcasecmp(file
, file_nameA
))
718 HeapFree(GetProcessHeap(), 0, file_nameA
);
723 HeapFree(GetProcessHeap(), 0, file_nameA
);
727 static Family
*find_family_from_name(const WCHAR
*name
)
731 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
733 if(!strcmpiW(family
->FamilyName
, name
))
740 static void DumpSubstList(void)
744 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
746 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
747 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
748 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
750 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
751 debugstr_w(psub
->to
.name
));
756 static LPWSTR
strdupW(LPCWSTR p
)
759 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
760 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
765 static LPSTR
strdupA(LPCSTR p
)
768 DWORD len
= (strlen(p
) + 1);
769 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
774 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
779 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
781 if(!strcmpiW(element
->from
.name
, from_name
) &&
782 (element
->from
.charset
== from_charset
||
783 element
->from
.charset
== -1))
790 #define ADD_FONT_SUBST_FORCE 1
792 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
794 FontSubst
*from_exist
, *to_exist
;
796 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
798 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
800 list_remove(&from_exist
->entry
);
801 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
802 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
803 HeapFree(GetProcessHeap(), 0, from_exist
);
809 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
813 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
814 subst
->to
.name
= strdupW(to_exist
->to
.name
);
817 list_add_tail(subst_list
, &subst
->entry
);
822 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
823 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
824 HeapFree(GetProcessHeap(), 0, subst
);
828 static void split_subst_info(NameCs
*nc
, LPSTR str
)
830 CHAR
*p
= strrchr(str
, ',');
835 nc
->charset
= strtol(p
+1, NULL
, 10);
838 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
839 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
840 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
843 static void LoadSubstList(void)
847 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
851 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
852 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
853 &hkey
) == ERROR_SUCCESS
) {
855 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
856 &valuelen
, &datalen
, NULL
, NULL
);
858 valuelen
++; /* returned value doesn't include room for '\0' */
859 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
860 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
864 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
865 &dlen
) == ERROR_SUCCESS
) {
866 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
868 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
869 split_subst_info(&psub
->from
, value
);
870 split_subst_info(&psub
->to
, data
);
872 /* Win 2000 doesn't allow mapping between different charsets
873 or mapping of DEFAULT_CHARSET */
874 if((psub
->to
.charset
!= psub
->from
.charset
) ||
875 psub
->to
.charset
== DEFAULT_CHARSET
) {
876 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
877 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
878 HeapFree(GetProcessHeap(), 0, psub
);
880 add_font_subst(&font_subst_list
, psub
, 0);
882 /* reset dlen and vlen */
886 HeapFree(GetProcessHeap(), 0, data
);
887 HeapFree(GetProcessHeap(), 0, value
);
892 static WCHAR
*get_familyname(FT_Face ft_face
)
894 WCHAR
*family
= NULL
;
896 FT_UInt num_names
, name_index
, i
;
898 if(FT_IS_SFNT(ft_face
))
900 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
902 for(name_index
= 0; name_index
< num_names
; name_index
++)
904 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
906 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
907 (name
.language_id
== GetUserDefaultLCID()) &&
908 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
909 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
911 /* String is not nul terminated and string_len is a byte length. */
912 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
913 for(i
= 0; i
< name
.string_len
/ 2; i
++)
915 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
916 family
[i
] = GET_BE_WORD(*tmp
);
920 TRACE("Got localised name %s\n", debugstr_w(family
));
931 #define ADDFONT_EXTERNAL_FONT 0x01
932 #define ADDFONT_FORCE_BITMAP 0x02
933 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
937 TT_Header
*pHeader
= NULL
;
938 WCHAR
*english_family
, *localised_family
, *StyleW
;
942 struct list
*family_elem_ptr
, *face_elem_ptr
;
944 FT_Long face_index
= 0, num_faces
;
945 #ifdef HAVE_FREETYPE_FTWINFNT_H
946 FT_WinFNT_HeaderRec winfnt_header
;
948 int i
, bitmap_num
, internal_leading
;
951 #ifdef HAVE_CARBON_CARBON_H
954 char **mac_list
= expand_mac_font(file
);
957 BOOL had_one
= FALSE
;
959 for(cursor
= mac_list
; *cursor
; cursor
++)
962 AddFontFileToList(*cursor
, NULL
, NULL
, flags
);
963 HeapFree(GetProcessHeap(), 0, *cursor
);
965 HeapFree(GetProcessHeap(), 0, mac_list
);
970 #endif /* HAVE_CARBON_CARBON_H */
973 char *family_name
= fake_family
;
975 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
976 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
977 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
981 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*/
982 WARN("Ignoring font %s\n", debugstr_a(file
));
983 pFT_Done_Face(ft_face
);
987 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
988 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
989 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file
));
990 pFT_Done_Face(ft_face
);
994 if(FT_IS_SFNT(ft_face
) && (!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
995 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
996 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))) {
997 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
998 "Skipping this font.\n", debugstr_a(file
));
999 pFT_Done_Face(ft_face
);
1003 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1004 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
1005 pFT_Done_Face(ft_face
);
1011 localised_family
= get_familyname(ft_face
);
1012 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1014 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1015 HeapFree(GetProcessHeap(), 0, localised_family
);
1016 num_faces
= ft_face
->num_faces
;
1017 pFT_Done_Face(ft_face
);
1020 HeapFree(GetProcessHeap(), 0, localised_family
);
1024 family_name
= ft_face
->family_name
;
1028 My_FT_Bitmap_Size
*size
= NULL
;
1030 if(!FT_IS_SCALABLE(ft_face
))
1031 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1033 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1034 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1035 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1037 localised_family
= NULL
;
1039 localised_family
= get_familyname(ft_face
);
1040 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1041 HeapFree(GetProcessHeap(), 0, localised_family
);
1042 localised_family
= NULL
;
1047 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1048 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1049 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1054 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1055 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1056 list_init(&family
->faces
);
1057 list_add_tail(&font_list
, &family
->entry
);
1059 if(localised_family
) {
1060 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1061 subst
->from
.name
= strdupW(english_family
);
1062 subst
->from
.charset
= -1;
1063 subst
->to
.name
= strdupW(localised_family
);
1064 subst
->to
.charset
= -1;
1065 add_font_subst(&font_subst_list
, subst
, 0);
1068 HeapFree(GetProcessHeap(), 0, localised_family
);
1069 HeapFree(GetProcessHeap(), 0, english_family
);
1071 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1072 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1073 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1075 internal_leading
= 0;
1076 memset(&fs
, 0, sizeof(fs
));
1078 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1080 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1081 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1082 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1083 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1084 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1085 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1086 if(pOS2
->version
== 0) {
1089 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1092 fs
.fsCsb
[0] |= 1L << 31;
1095 #ifdef HAVE_FREETYPE_FTWINFNT_H
1096 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1098 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1099 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1100 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1101 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
1102 internal_leading
= winfnt_header
.internal_leading
;
1106 face_elem_ptr
= list_head(&family
->faces
);
1107 while(face_elem_ptr
) {
1108 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1109 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1110 if(!strcmpW(face
->StyleName
, StyleW
) &&
1111 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1112 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1113 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1114 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1117 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1118 HeapFree(GetProcessHeap(), 0, StyleW
);
1119 pFT_Done_Face(ft_face
);
1122 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1123 TRACE("Original font is newer so skipping this one\n");
1124 HeapFree(GetProcessHeap(), 0, StyleW
);
1125 pFT_Done_Face(ft_face
);
1128 TRACE("Replacing original with this one\n");
1129 list_remove(&face
->entry
);
1130 HeapFree(GetProcessHeap(), 0, face
->file
);
1131 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1132 HeapFree(GetProcessHeap(), 0, face
);
1137 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1138 list_add_tail(&family
->faces
, &face
->entry
);
1139 face
->StyleName
= StyleW
;
1140 face
->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
1141 strcpy(face
->file
, file
);
1142 face
->face_index
= face_index
;
1143 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
1144 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
1145 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1146 face
->family
= family
;
1147 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1148 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
1149 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1151 if(FT_IS_SCALABLE(ft_face
)) {
1152 memset(&face
->size
, 0, sizeof(face
->size
));
1153 face
->scalable
= TRUE
;
1155 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1156 size
->height
, size
->width
, size
->size
>> 6,
1157 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1158 face
->size
.height
= size
->height
;
1159 face
->size
.width
= size
->width
;
1160 face
->size
.size
= size
->size
;
1161 face
->size
.x_ppem
= size
->x_ppem
;
1162 face
->size
.y_ppem
= size
->y_ppem
;
1163 face
->size
.internal_leading
= internal_leading
;
1164 face
->scalable
= FALSE
;
1167 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1168 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1169 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1170 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1173 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1174 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1175 switch(ft_face
->charmaps
[i
]->encoding
) {
1176 case FT_ENCODING_UNICODE
:
1177 case FT_ENCODING_APPLE_ROMAN
:
1178 face
->fs
.fsCsb
[0] |= 1;
1180 case FT_ENCODING_MS_SYMBOL
:
1181 face
->fs
.fsCsb
[0] |= 1L << 31;
1189 if(face
->fs
.fsCsb
[0] & ~(1L << 31))
1190 have_installed_roman_font
= TRUE
;
1191 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1193 num_faces
= ft_face
->num_faces
;
1194 pFT_Done_Face(ft_face
);
1195 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1196 debugstr_w(StyleW
));
1197 } while(num_faces
> ++face_index
);
1201 static void DumpFontList(void)
1205 struct list
*family_elem_ptr
, *face_elem_ptr
;
1207 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1208 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1209 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1210 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1211 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1212 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1214 TRACE(" %d", face
->size
.height
);
1221 /***********************************************************
1222 * The replacement list is a way to map an entire font
1223 * family onto another family. For example adding
1225 * [HKCU\Software\Wine\Fonts\Replacements]
1226 * "Wingdings"="Winedings"
1228 * would enumerate the Winedings font both as Winedings and
1229 * Wingdings. However if a real Wingdings font is present the
1230 * replacement does not take place.
1233 static void LoadReplaceList(void)
1236 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1241 struct list
*family_elem_ptr
, *face_elem_ptr
;
1244 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1245 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1247 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1248 &valuelen
, &datalen
, NULL
, NULL
);
1250 valuelen
++; /* returned value doesn't include room for '\0' */
1251 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1252 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1256 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1257 &dlen
) == ERROR_SUCCESS
) {
1258 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1259 /* "NewName"="Oldname" */
1260 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1262 /* Find the old family and hence all of the font files
1264 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1265 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1266 if(!strcmpiW(family
->FamilyName
, data
)) {
1267 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1268 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1269 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1270 debugstr_w(face
->StyleName
), familyA
);
1271 /* Now add a new entry with the new family name */
1272 AddFontFileToList(face
->file
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1277 /* reset dlen and vlen */
1281 HeapFree(GetProcessHeap(), 0, data
);
1282 HeapFree(GetProcessHeap(), 0, value
);
1287 /*************************************************************
1290 static BOOL
init_system_links(void)
1292 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1293 'W','i','n','d','o','w','s',' ','N','T','\\',
1294 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1295 'S','y','s','t','e','m','L','i','n','k',0};
1298 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1299 WCHAR
*value
, *data
;
1300 WCHAR
*entry
, *next
;
1301 SYSTEM_LINKS
*font_link
, *system_font_link
;
1302 CHILD_FONT
*child_font
;
1303 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1304 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1305 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1311 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1313 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1314 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1315 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1316 val_len
= max_val
+ 1;
1317 data_len
= max_data
;
1319 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1321 TRACE("%s:\n", debugstr_w(value
));
1323 memset(&fs
, 0, sizeof(fs
));
1324 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1325 psub
= get_font_subst(&font_subst_list
, value
, -1);
1326 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1327 list_init(&font_link
->links
);
1328 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1331 CHILD_FONT
*child_font
;
1333 TRACE("\t%s\n", debugstr_w(entry
));
1335 next
= entry
+ strlenW(entry
) + 1;
1337 face_name
= strchrW(entry
, ',');
1341 while(isspaceW(*face_name
))
1344 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1346 face_name
= psub
->to
.name
;
1348 face
= find_face_from_filename(entry
, face_name
);
1351 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1355 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1356 child_font
->face
= face
;
1357 child_font
->font
= NULL
;
1358 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1359 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1360 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1361 list_add_tail(&font_link
->links
, &child_font
->entry
);
1363 family
= find_family_from_name(font_link
->font_name
);
1366 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1368 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
1371 list_add_tail(&system_links
, &font_link
->entry
);
1372 val_len
= max_val
+ 1;
1373 data_len
= max_data
;
1376 HeapFree(GetProcessHeap(), 0, value
);
1377 HeapFree(GetProcessHeap(), 0, data
);
1381 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1384 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1385 system_font_link
->font_name
= strdupW(System
);
1386 list_init(&system_font_link
->links
);
1388 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1391 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1392 child_font
->face
= face
;
1393 child_font
->font
= NULL
;
1394 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1395 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1397 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1399 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1401 CHILD_FONT
*font_link_entry
;
1402 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1404 CHILD_FONT
*new_child
;
1405 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1406 new_child
->face
= font_link_entry
->face
;
1407 new_child
->font
= NULL
;
1408 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1413 list_add_tail(&system_links
, &system_font_link
->entry
);
1417 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1420 struct dirent
*dent
;
1421 char path
[MAX_PATH
];
1423 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1425 dir
= opendir(dirname
);
1427 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1430 while((dent
= readdir(dir
)) != NULL
) {
1431 struct stat statbuf
;
1433 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1436 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1438 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1440 if(stat(path
, &statbuf
) == -1)
1442 WARN("Can't stat %s\n", debugstr_a(path
));
1445 if(S_ISDIR(statbuf
.st_mode
))
1446 ReadFontDir(path
, external_fonts
);
1448 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1454 static void load_fontconfig_fonts(void)
1456 #ifdef SONAME_LIBFONTCONFIG
1457 void *fc_handle
= NULL
;
1466 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1468 TRACE("Wine cannot find the fontconfig library (%s).\n",
1469 SONAME_LIBFONTCONFIG
);
1472 #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;}
1473 LOAD_FUNCPTR(FcConfigGetCurrent
);
1474 LOAD_FUNCPTR(FcFontList
);
1475 LOAD_FUNCPTR(FcFontSetDestroy
);
1476 LOAD_FUNCPTR(FcInit
);
1477 LOAD_FUNCPTR(FcObjectSetAdd
);
1478 LOAD_FUNCPTR(FcObjectSetCreate
);
1479 LOAD_FUNCPTR(FcObjectSetDestroy
);
1480 LOAD_FUNCPTR(FcPatternCreate
);
1481 LOAD_FUNCPTR(FcPatternDestroy
);
1482 LOAD_FUNCPTR(FcPatternGetBool
);
1483 LOAD_FUNCPTR(FcPatternGetString
);
1486 if(!pFcInit()) return;
1488 config
= pFcConfigGetCurrent();
1489 pat
= pFcPatternCreate();
1490 os
= pFcObjectSetCreate();
1491 pFcObjectSetAdd(os
, FC_FILE
);
1492 pFcObjectSetAdd(os
, FC_SCALABLE
);
1493 fontset
= pFcFontList(config
, pat
, os
);
1494 if(!fontset
) return;
1495 for(i
= 0; i
< fontset
->nfont
; i
++) {
1498 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1500 TRACE("fontconfig: %s\n", file
);
1502 /* We're just interested in OT/TT fonts for now, so this hack just
1503 picks up the scalable fonts without extensions .pf[ab] to save time
1504 loading every other font */
1506 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1508 TRACE("not scalable\n");
1512 len
= strlen( file
);
1513 if(len
< 4) continue;
1514 ext
= &file
[ len
- 3 ];
1515 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1516 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1518 pFcFontSetDestroy(fontset
);
1519 pFcObjectSetDestroy(os
);
1520 pFcPatternDestroy(pat
);
1526 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1529 const char *data_dir
= wine_get_data_dir();
1531 if (!data_dir
) data_dir
= wine_get_build_dir();
1538 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1540 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1542 strcpy(unix_name
, data_dir
);
1543 strcat(unix_name
, "/fonts/");
1545 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1547 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1548 HeapFree(GetProcessHeap(), 0, unix_name
);
1553 static void load_system_fonts(void)
1556 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1557 const WCHAR
* const *value
;
1559 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1562 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1563 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1564 strcatW(windowsdir
, fontsW
);
1565 for(value
= SystemFontValues
; *value
; value
++) {
1566 dlen
= sizeof(data
);
1567 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1571 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1572 if((unixname
= wine_get_unix_file_name(pathW
))) {
1573 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1574 HeapFree(GetProcessHeap(), 0, unixname
);
1577 load_font_from_data_dir(data
);
1584 /*************************************************************
1586 * This adds registry entries for any externally loaded fonts
1587 * (fonts from fontconfig or FontDirs). It also deletes entries
1588 * of no longer existing fonts.
1591 static void update_reg_entries(void)
1593 HKEY winkey
= 0, externalkey
= 0;
1596 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
1599 struct list
*family_elem_ptr
, *face_elem_ptr
;
1601 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1602 static const WCHAR spaceW
[] = {' ', '\0'};
1605 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1606 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
1607 ERR("Can't create Windows font reg key\n");
1610 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1611 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
1612 ERR("Can't create external font reg key\n");
1616 /* Delete all external fonts added last time */
1618 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1619 &valuelen
, &datalen
, NULL
, NULL
);
1620 valuelen
++; /* returned value doesn't include room for '\0' */
1621 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1622 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1624 dlen
= datalen
* sizeof(WCHAR
);
1627 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1628 &dlen
) == ERROR_SUCCESS
) {
1630 RegDeleteValueW(winkey
, valueW
);
1631 /* reset dlen and vlen */
1635 HeapFree(GetProcessHeap(), 0, data
);
1636 HeapFree(GetProcessHeap(), 0, valueW
);
1638 /* Delete the old external fonts key */
1639 RegCloseKey(externalkey
);
1641 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1643 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1644 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1645 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
1646 ERR("Can't create external font reg key\n");
1650 /* enumerate the fonts and add external ones to the two keys */
1652 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1653 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1654 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1655 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1656 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1657 if(!face
->external
) continue;
1659 if(strcmpiW(face
->StyleName
, RegularW
))
1660 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1661 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1662 strcpyW(valueW
, family
->FamilyName
);
1663 if(len
!= len_fam
) {
1664 strcatW(valueW
, spaceW
);
1665 strcatW(valueW
, face
->StyleName
);
1667 strcatW(valueW
, TrueType
);
1668 if((path
= strrchr(face
->file
, '/')) == NULL
)
1672 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1674 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1675 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1676 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1677 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1679 HeapFree(GetProcessHeap(), 0, file
);
1680 HeapFree(GetProcessHeap(), 0, valueW
);
1685 RegCloseKey(externalkey
);
1687 RegCloseKey(winkey
);
1692 /*************************************************************
1693 * WineEngAddFontResourceEx
1696 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1698 if (ft_handle
) /* do it only if we have freetype up and running */
1703 FIXME("Ignoring flags %x\n", flags
);
1705 if((unixname
= wine_get_unix_file_name(file
)))
1707 INT ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1708 HeapFree(GetProcessHeap(), 0, unixname
);
1715 /*************************************************************
1716 * WineEngRemoveFontResourceEx
1719 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1725 static const struct nls_update_font_list
1727 UINT ansi_cp
, oem_cp
;
1728 const char *oem
, *fixed
, *system
;
1729 const char *courier
, *serif
, *small
, *sserif
;
1730 /* these are for font substitute */
1731 const char *shelldlg
, *tmsrmn
;
1732 } nls_update_font_list
[] =
1734 /* Latin 1 (United States) */
1735 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1736 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1737 "Tahoma","Times New Roman",
1739 /* Latin 1 (Multilingual) */
1740 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1741 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1742 "Tahoma","Times New Roman", /* FIXME unverified */
1744 /* Eastern Europe */
1745 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1746 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1747 "Tahoma","Times New Roman", /* FIXME unverified */
1750 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1751 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1752 "Tahoma","Times New Roman", /* FIXME unverified */
1755 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1756 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1757 "Tahoma","Times New Roman", /* FIXME unverified */
1760 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1761 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1762 "Tahoma","Times New Roman", /* FIXME unverified */
1765 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1766 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1767 "Tahoma","Times New Roman", /* FIXME unverified */
1770 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1771 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1772 "Tahoma","Times New Roman", /* FIXME unverified */
1775 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1776 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1777 "Tahoma","Times New Roman", /* FIXME unverified */
1780 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1781 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1782 "Tahoma","Times New Roman", /* FIXME unverified */
1785 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1786 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1787 "Tahoma","Times New Roman", /* FIXME unverified */
1790 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1791 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1792 "MS UI Gothic","MS Serif",
1794 /* Chinese Simplified */
1795 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1796 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1797 "Tahoma", "Times New Roman", /* FIXME unverified */
1800 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1801 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1804 /* Chinese Traditional */
1805 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1806 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1807 "Tahoma", "Times New Roman", /* FIXME unverified */
1811 static inline HKEY
create_fonts_NT_registry_key(void)
1815 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
1816 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1820 static inline HKEY
create_fonts_9x_registry_key(void)
1824 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
1825 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1829 static inline HKEY
create_config_fonts_registry_key(void)
1833 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
1834 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1838 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
1840 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
1841 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
1842 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
1843 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
1846 static void update_font_info(void)
1848 char buf
[40], cpbuf
[40];
1851 UINT i
, ansi_cp
= 0, oem_cp
= 0;
1853 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
1856 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1857 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
1858 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1859 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
1860 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
1863 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
1865 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
1870 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
1872 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
1874 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
1877 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
1879 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
1880 nls_update_font_list
[i
].oem_cp
== oem_cp
)
1884 hkey
= create_config_fonts_registry_key();
1885 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
1886 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
1887 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
1890 hkey
= create_fonts_NT_registry_key();
1891 add_font_list(hkey
, &nls_update_font_list
[i
]);
1894 hkey
= create_fonts_9x_registry_key();
1895 add_font_list(hkey
, &nls_update_font_list
[i
]);
1898 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
1900 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
1901 strlen(nls_update_font_list
[i
].shelldlg
)+1);
1902 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
1903 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
1909 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
1912 /*************************************************************
1915 * Initialize FreeType library and create a list of available faces
1917 BOOL
WineEngInit(void)
1919 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
1920 static const WCHAR pathW
[] = {'P','a','t','h',0};
1922 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1924 WCHAR windowsdir
[MAX_PATH
];
1927 const char *data_dir
;
1931 /* update locale dependent font info in registry */
1934 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
1937 "Wine cannot find the FreeType font library. To enable Wine to\n"
1938 "use TrueType fonts please install a version of FreeType greater than\n"
1939 "or equal to 2.0.5.\n"
1940 "http://www.freetype.org\n");
1944 #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;}
1946 LOAD_FUNCPTR(FT_Vector_Unit
)
1947 LOAD_FUNCPTR(FT_Done_Face
)
1948 LOAD_FUNCPTR(FT_Get_Char_Index
)
1949 LOAD_FUNCPTR(FT_Get_Module
)
1950 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
1951 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
1952 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1953 LOAD_FUNCPTR(FT_Init_FreeType
)
1954 LOAD_FUNCPTR(FT_Load_Glyph
)
1955 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1956 LOAD_FUNCPTR(FT_MulFix
)
1957 LOAD_FUNCPTR(FT_New_Face
)
1958 LOAD_FUNCPTR(FT_New_Memory_Face
)
1959 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1960 LOAD_FUNCPTR(FT_Outline_Transform
)
1961 LOAD_FUNCPTR(FT_Outline_Translate
)
1962 LOAD_FUNCPTR(FT_Select_Charmap
)
1963 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1964 LOAD_FUNCPTR(FT_Vector_Transform
)
1967 /* Don't warn if this one is missing */
1968 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
1969 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
1970 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
1971 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
1972 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
1973 #ifdef HAVE_FREETYPE_FTWINFNT_H
1974 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
1976 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
1977 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
1978 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1979 <= 2.0.3 has FT_Sqrt64 */
1983 if(pFT_Init_FreeType(&library
) != 0) {
1984 ERR("Can't init FreeType library\n");
1985 wine_dlclose(ft_handle
, NULL
, 0);
1989 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
1990 if (pFT_Library_Version
)
1992 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1994 if (FT_Version
.major
<=0)
2000 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2001 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2002 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2003 ((FT_Version
.patch
) & 0x0000ff);
2005 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2006 ERR("Failed to create font mutex\n");
2009 WaitForSingleObject(font_mutex
, INFINITE
);
2011 /* load the system bitmap fonts */
2012 load_system_fonts();
2014 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2015 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2016 strcatW(windowsdir
, fontsW
);
2017 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2019 ReadFontDir(unixname
, FALSE
);
2020 HeapFree(GetProcessHeap(), 0, unixname
);
2023 /* load the system truetype fonts */
2024 data_dir
= wine_get_data_dir();
2025 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2026 strcpy(unixname
, data_dir
);
2027 strcat(unixname
, "/fonts/");
2028 ReadFontDir(unixname
, FALSE
);
2029 HeapFree(GetProcessHeap(), 0, unixname
);
2032 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2033 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2034 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2036 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2037 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2038 &hkey
) == ERROR_SUCCESS
) {
2040 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2041 &valuelen
, &datalen
, NULL
, NULL
);
2043 valuelen
++; /* returned value doesn't include room for '\0' */
2044 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2045 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2048 dlen
= datalen
* sizeof(WCHAR
);
2050 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2051 &dlen
) == ERROR_SUCCESS
) {
2052 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2054 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2056 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2057 HeapFree(GetProcessHeap(), 0, unixname
);
2060 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2062 WCHAR pathW
[MAX_PATH
];
2063 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2066 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2067 if((unixname
= wine_get_unix_file_name(pathW
)))
2069 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2070 HeapFree(GetProcessHeap(), 0, unixname
);
2073 load_font_from_data_dir(data
);
2075 /* reset dlen and vlen */
2080 HeapFree(GetProcessHeap(), 0, data
);
2081 HeapFree(GetProcessHeap(), 0, valueW
);
2085 load_fontconfig_fonts();
2087 /* then look in any directories that we've specified in the config file */
2088 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2089 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2095 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2097 len
+= sizeof(WCHAR
);
2098 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2099 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2101 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2102 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2103 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2104 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2108 LPSTR next
= strchr( ptr
, ':' );
2109 if (next
) *next
++ = 0;
2110 ReadFontDir( ptr
, TRUE
);
2113 HeapFree( GetProcessHeap(), 0, valueA
);
2115 HeapFree( GetProcessHeap(), 0, valueW
);
2124 update_reg_entries();
2126 init_system_links();
2128 ReleaseMutex(font_mutex
);
2132 "Wine cannot find certain functions that it needs inside the FreeType\n"
2133 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2134 "FreeType to at least version 2.0.5.\n"
2135 "http://www.freetype.org\n");
2136 wine_dlclose(ft_handle
, NULL
, 0);
2142 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2145 TT_HoriHeader
*pHori
;
2149 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2150 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2152 if(height
== 0) height
= 16;
2154 /* Calc. height of EM square:
2156 * For +ve lfHeight we have
2157 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2158 * Re-arranging gives:
2159 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2161 * For -ve lfHeight we have
2163 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2164 * with il = winAscent + winDescent - units_per_em]
2169 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2170 ppem
= ft_face
->units_per_EM
* height
/
2171 (pHori
->Ascender
- pHori
->Descender
);
2173 ppem
= ft_face
->units_per_EM
* height
/
2174 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2182 static struct font_mapping
*map_font( const char *name
)
2184 struct font_mapping
*mapping
;
2188 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2189 if (fstat( fd
, &st
) == -1) goto error
;
2191 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2193 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2195 mapping
->refcount
++;
2200 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2203 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2206 if (mapping
->data
== MAP_FAILED
)
2208 HeapFree( GetProcessHeap(), 0, mapping
);
2211 mapping
->refcount
= 1;
2212 mapping
->dev
= st
.st_dev
;
2213 mapping
->ino
= st
.st_ino
;
2214 mapping
->size
= st
.st_size
;
2215 list_add_tail( &mappings_list
, &mapping
->entry
);
2223 static void unmap_font( struct font_mapping
*mapping
)
2225 if (!--mapping
->refcount
)
2227 list_remove( &mapping
->entry
);
2228 munmap( mapping
->data
, mapping
->size
);
2229 HeapFree( GetProcessHeap(), 0, mapping
);
2233 static LONG
load_VDMX(GdiFont
*, LONG
);
2235 static FT_Face
OpenFontFile(GdiFont
*font
, char *file
, FT_Long face_index
, LONG width
, LONG height
)
2240 TRACE("%s, %ld, %d x %d\n", debugstr_a(file
), face_index
, width
, height
);
2242 if (!(font
->mapping
= map_font( file
)))
2244 WARN("failed to map %s\n", debugstr_a(file
));
2248 err
= pFT_New_Memory_Face(library
, font
->mapping
->data
, font
->mapping
->size
, face_index
, &ft_face
);
2250 ERR("FT_New_Face rets %d\n", err
);
2254 /* set it here, as load_VDMX needs it */
2255 font
->ft_face
= ft_face
;
2257 if(FT_IS_SCALABLE(ft_face
)) {
2258 /* load the VDMX table if we have one */
2259 font
->ppem
= load_VDMX(font
, height
);
2261 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2263 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2264 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2266 font
->ppem
= height
;
2267 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2268 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2274 static int get_nearest_charset(Face
*face
, int *cp
)
2276 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2277 a single face with the requested charset. The idea is to check if
2278 the selected font supports the current ANSI codepage, if it does
2279 return the corresponding charset, else return the first charset */
2282 int acp
= GetACP(), i
;
2286 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2287 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2288 return csi
.ciCharset
;
2290 for(i
= 0; i
< 32; i
++) {
2292 if(face
->fs
.fsCsb
[0] & fs0
) {
2293 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2295 return csi
.ciCharset
;
2298 FIXME("TCI failing on %x\n", fs0
);
2302 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2303 face
->fs
.fsCsb
[0], face
->file
);
2305 return DEFAULT_CHARSET
;
2308 static GdiFont
*alloc_font(void)
2310 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2312 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2313 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2315 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2316 ret
->total_kern_pairs
= (DWORD
)-1;
2317 ret
->kern_pairs
= NULL
;
2318 list_init(&ret
->hfontlist
);
2319 list_init(&ret
->child_fonts
);
2323 static void free_font(GdiFont
*font
)
2325 struct list
*cursor
, *cursor2
;
2328 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2330 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2331 struct list
*first_hfont
;
2332 HFONTLIST
*hfontlist
;
2333 list_remove(cursor
);
2336 first_hfont
= list_head(&child
->font
->hfontlist
);
2337 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2338 DeleteObject(hfontlist
->hfont
);
2339 HeapFree(GetProcessHeap(), 0, hfontlist
);
2340 free_font(child
->font
);
2342 HeapFree(GetProcessHeap(), 0, child
);
2345 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2346 if (font
->mapping
) unmap_font( font
->mapping
);
2347 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2348 HeapFree(GetProcessHeap(), 0, font
->potm
);
2349 HeapFree(GetProcessHeap(), 0, font
->name
);
2350 for (i
= 0; i
< font
->gmsize
; i
++)
2351 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2352 HeapFree(GetProcessHeap(), 0, font
->gm
);
2353 HeapFree(GetProcessHeap(), 0, font
);
2357 /*************************************************************
2360 * load the vdmx entry for the specified height
2363 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2364 ( ( (FT_ULong)_x4 << 24 ) | \
2365 ( (FT_ULong)_x3 << 16 ) | \
2366 ( (FT_ULong)_x2 << 8 ) | \
2369 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2384 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2388 BYTE devXRatio
, devYRatio
;
2389 USHORT numRecs
, numRatios
;
2390 DWORD result
, offset
= -1;
2394 /* For documentation on VDMX records, see
2395 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2398 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2400 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2403 /* FIXME: need the real device aspect ratio */
2407 numRecs
= GET_BE_WORD(hdr
[1]);
2408 numRatios
= GET_BE_WORD(hdr
[2]);
2410 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2411 for(i
= 0; i
< numRatios
; i
++) {
2414 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2415 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2418 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2420 if((ratio
.xRatio
== 0 &&
2421 ratio
.yStartRatio
== 0 &&
2422 ratio
.yEndRatio
== 0) ||
2423 (devXRatio
== ratio
.xRatio
&&
2424 devYRatio
>= ratio
.yStartRatio
&&
2425 devYRatio
<= ratio
.yEndRatio
))
2427 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2428 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2429 offset
= GET_BE_WORD(tmp
);
2435 FIXME("No suitable ratio found\n");
2439 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2441 BYTE startsz
, endsz
;
2444 recs
= GET_BE_WORD(group
.recs
);
2445 startsz
= group
.startsz
;
2446 endsz
= group
.endsz
;
2448 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2450 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2451 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2452 if(result
== GDI_ERROR
) {
2453 FIXME("Failed to retrieve vTable\n");
2458 for(i
= 0; i
< recs
; i
++) {
2459 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2460 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2461 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2463 if(yMax
+ -yMin
== height
) {
2466 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2469 if(yMax
+ -yMin
> height
) {
2472 goto end
; /* failed */
2474 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2475 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2476 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2477 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2483 TRACE("ppem not found for height %d\n", height
);
2487 if(ppem
< startsz
|| ppem
> endsz
)
2490 for(i
= 0; i
< recs
; i
++) {
2492 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2494 if(yPelHeight
> ppem
)
2497 if(yPelHeight
== ppem
) {
2498 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2499 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2500 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2506 HeapFree(GetProcessHeap(), 0, vTable
);
2512 static BOOL
fontcmp(GdiFont
*font
, FONT_DESC
*fd
)
2514 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2515 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2516 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2517 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2518 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2521 static void calc_hash(FONT_DESC
*pfd
)
2523 DWORD hash
= 0, *ptr
, two_chars
;
2527 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2529 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2531 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2533 pwc
= (WCHAR
*)&two_chars
;
2535 *pwc
= toupperW(*pwc
);
2537 *pwc
= toupperW(*pwc
);
2541 hash
^= !pfd
->can_use_bitmap
;
2546 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2551 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2553 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
2554 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2555 fd
.can_use_bitmap
= can_use_bitmap
;
2558 /* try the in-use list */
2559 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2560 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2561 if(!fontcmp(ret
, &fd
)) {
2562 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2563 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2564 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2565 if(hflist
->hfont
== hfont
)
2568 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2569 hflist
->hfont
= hfont
;
2570 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2575 /* then the unused list */
2576 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2577 while(font_elem_ptr
) {
2578 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2579 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2580 if(!fontcmp(ret
, &fd
)) {
2581 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2582 assert(list_empty(&ret
->hfontlist
));
2583 TRACE("Found %p in unused list\n", ret
);
2584 list_remove(&ret
->entry
);
2585 list_add_head(&gdi_font_list
, &ret
->entry
);
2586 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2587 hflist
->hfont
= hfont
;
2588 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2596 /*************************************************************
2597 * create_child_font_list
2599 static BOOL
create_child_font_list(GdiFont
*font
)
2602 SYSTEM_LINKS
*font_link
;
2603 CHILD_FONT
*font_link_entry
, *new_child
;
2605 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2607 if(!strcmpW(font_link
->font_name
, font
->name
))
2609 TRACE("found entry in system list\n");
2610 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2612 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2613 new_child
->face
= font_link_entry
->face
;
2614 new_child
->font
= NULL
;
2615 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2616 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
2626 /*************************************************************
2627 * WineEngCreateFontInstance
2630 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2633 Face
*face
, *best
, *best_bitmap
;
2634 Family
*family
, *last_resort_family
;
2635 struct list
*family_elem_ptr
, *face_elem_ptr
;
2636 INT height
, width
= 0;
2637 unsigned int score
= 0, new_score
;
2638 signed int diff
= 0, newdiff
;
2639 BOOL bd
, it
, can_use_bitmap
;
2644 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2646 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2647 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2648 if(hflist
->hfont
== hfont
)
2652 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
2653 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2655 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2656 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2657 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2660 /* check the cache first */
2661 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2662 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2666 TRACE("not in cache\n");
2667 if(list_empty(&font_list
)) /* No fonts installed */
2669 TRACE("No fonts installed\n");
2672 if(!have_installed_roman_font
)
2674 TRACE("No roman font installed\n");
2680 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
2681 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
2682 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
2683 calc_hash(&ret
->font_desc
);
2684 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2685 hflist
->hfont
= hfont
;
2686 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2689 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2690 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2691 original value lfCharSet. Note this is a special case for
2692 Symbol and doesn't happen at least for "Wingdings*" */
2694 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
2695 lf
.lfCharSet
= SYMBOL_CHARSET
;
2697 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
2698 switch(lf
.lfCharSet
) {
2699 case DEFAULT_CHARSET
:
2700 csi
.fs
.fsCsb
[0] = 0;
2703 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
2704 csi
.fs
.fsCsb
[0] = 0;
2710 if(lf
.lfFaceName
[0] != '\0') {
2712 SYSTEM_LINKS
*font_link
;
2713 CHILD_FONT
*font_link_entry
;
2715 psub
= get_font_subst(&font_subst_list
, lf
.lfFaceName
, lf
.lfCharSet
);
2718 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
2719 debugstr_w(psub
->to
.name
));
2720 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2723 /* We want a match on name and charset or just name if
2724 charset was DEFAULT_CHARSET. If the latter then
2725 we fixup the returned charset later in get_nearest_charset
2726 where we'll either use the charset of the current ansi codepage
2727 or if that's unavailable the first charset that the font supports.
2729 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2730 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2731 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2732 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2733 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2734 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2735 if(face
->scalable
|| can_use_bitmap
)
2742 * Try check the SystemLink list first for a replacement font.
2743 * We may find good replacements there.
2745 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2747 if(!strcmpiW(font_link
->font_name
, lf
.lfFaceName
))
2749 TRACE("found entry in system list\n");
2750 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2752 face
= font_link_entry
->face
;
2753 family
= face
->family
;
2754 if(csi
.fs
.fsCsb
[0] &
2755 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
2757 if(face
->scalable
|| can_use_bitmap
)
2765 /* If requested charset was DEFAULT_CHARSET then try using charset
2766 corresponding to the current ansi codepage */
2767 if(!csi
.fs
.fsCsb
[0]) {
2769 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
2770 FIXME("TCI failed on codepage %d\n", acp
);
2771 csi
.fs
.fsCsb
[0] = 0;
2773 lf
.lfCharSet
= csi
.ciCharset
;
2776 /* Face families are in the top 4 bits of lfPitchAndFamily,
2777 so mask with 0xF0 before testing */
2779 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
2780 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
2781 strcpyW(lf
.lfFaceName
, defFixed
);
2782 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
2783 strcpyW(lf
.lfFaceName
, defSerif
);
2784 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
2785 strcpyW(lf
.lfFaceName
, defSans
);
2787 strcpyW(lf
.lfFaceName
, defSans
);
2788 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2789 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2790 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2791 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2792 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2793 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2794 if(face
->scalable
|| can_use_bitmap
)
2800 last_resort_family
= NULL
;
2801 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2802 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2803 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2804 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2805 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
2808 if(can_use_bitmap
&& !last_resort_family
)
2809 last_resort_family
= family
;
2814 if(last_resort_family
) {
2815 family
= last_resort_family
;
2816 csi
.fs
.fsCsb
[0] = 0;
2820 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2821 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2822 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2823 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2824 if(face
->scalable
) {
2825 csi
.fs
.fsCsb
[0] = 0;
2826 WARN("just using first face for now\n");
2829 if(can_use_bitmap
&& !last_resort_family
)
2830 last_resort_family
= family
;
2833 if(!last_resort_family
) {
2834 FIXME("can't find a single appropriate font - bailing\n");
2839 WARN("could only find a bitmap font - this will probably look awful!\n");
2840 family
= last_resort_family
;
2841 csi
.fs
.fsCsb
[0] = 0;
2844 it
= lf
.lfItalic
? 1 : 0;
2845 bd
= lf
.lfWeight
> 550 ? 1 : 0;
2847 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
2848 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
2850 face
= best
= best_bitmap
= NULL
;
2851 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2853 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2855 new_score
= (face
->Italic
^ it
) + (face
->Bold
^ bd
);
2856 if(!best
|| new_score
<= score
)
2858 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2859 face
->Italic
, face
->Bold
, it
, bd
);
2862 if(best
->scalable
&& score
== 0) break;
2866 newdiff
= height
- (signed int)(best
->size
.height
);
2868 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
2869 if(!best_bitmap
|| new_score
< score
||
2870 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
2872 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
2875 if(score
== 0 && diff
== 0) break;
2882 face
= best
->scalable
? best
: best_bitmap
;
2883 ret
->fake_italic
= (it
&& !face
->Italic
);
2884 ret
->fake_bold
= (bd
&& !face
->Bold
);
2886 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
2888 if(csi
.fs
.fsCsb
[0]) {
2889 ret
->charset
= lf
.lfCharSet
;
2890 ret
->codepage
= csi
.ciACP
;
2893 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
2895 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family
->FamilyName
),
2896 debugstr_w(face
->StyleName
), face
->file
, face
->face_index
);
2898 if(!face
->scalable
) {
2899 width
= face
->size
.x_ppem
>> 6;
2900 height
= face
->size
.y_ppem
>> 6;
2902 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
, width
, height
);
2910 if (ret
->charset
== SYMBOL_CHARSET
&&
2911 !pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
2914 else if (!pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
2918 pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
2921 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
2922 ret
->name
= strdupW(family
->FamilyName
);
2923 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
2924 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
2925 create_child_font_list(ret
);
2927 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
2929 ret
->aveWidth
= FT_IS_SCALABLE(ret
->ft_face
) ? abs(lf
.lfWidth
) : 0;
2930 list_add_head(&gdi_font_list
, &ret
->entry
);
2934 static void dump_gdi_font_list(void)
2937 struct list
*elem_ptr
;
2939 TRACE("---------- gdiFont Cache ----------\n");
2940 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
2941 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2942 TRACE("gdiFont=%p %s %d\n",
2943 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2946 TRACE("---------- Unused gdiFont Cache ----------\n");
2947 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
2948 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2949 TRACE("gdiFont=%p %s %d\n",
2950 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2954 /*************************************************************
2955 * WineEngDestroyFontInstance
2957 * free the gdiFont associated with this handle
2960 BOOL
WineEngDestroyFontInstance(HFONT handle
)
2965 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2968 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
2970 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
2971 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2972 if(hflist
->hfont
== handle
)
2974 TRACE("removing child font %p from child list\n", gdiFont
);
2975 list_remove(&gdiFont
->entry
);
2980 TRACE("destroying hfont=%p\n", handle
);
2982 dump_gdi_font_list();
2984 font_elem_ptr
= list_head(&gdi_font_list
);
2985 while(font_elem_ptr
) {
2986 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2987 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
2989 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
2990 while(hfontlist_elem_ptr
) {
2991 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2992 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
2993 if(hflist
->hfont
== handle
) {
2994 list_remove(&hflist
->entry
);
2995 HeapFree(GetProcessHeap(), 0, hflist
);
2999 if(list_empty(&gdiFont
->hfontlist
)) {
3000 TRACE("Moving to Unused list\n");
3001 list_remove(&gdiFont
->entry
);
3002 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3007 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3008 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3009 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3010 while(font_elem_ptr
) {
3011 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3012 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3013 TRACE("freeing %p\n", gdiFont
);
3014 list_remove(&gdiFont
->entry
);
3020 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3021 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3023 OUTLINETEXTMETRICW
*potm
= NULL
;
3025 TEXTMETRICW tm
, *ptm
;
3026 GdiFont
*font
= alloc_font();
3029 if(face
->scalable
) {
3033 height
= face
->size
.y_ppem
>> 6;
3034 width
= face
->size
.x_ppem
>> 6;
3037 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, width
, height
)))
3043 font
->name
= strdupW(face
->family
->FamilyName
);
3045 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
3047 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
3049 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3050 WineEngGetOutlineTextMetrics(font
, size
, potm
);
3051 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
3053 WineEngGetTextMetrics(font
, &tm
);
3057 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
3058 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
3059 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
3060 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
3061 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
3062 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
3063 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
3064 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
3065 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
3066 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
3067 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
3068 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
3069 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
3070 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
3071 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
3072 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
3073 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
3074 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
3075 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
3076 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
3077 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
3078 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3079 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3080 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3082 *ptype
= ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
3083 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
3084 *ptype
|= RASTER_FONTTYPE
;
3086 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
3087 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
3088 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
3090 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3091 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3092 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
3095 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
3097 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3098 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
3100 lstrcpynW(pelf
->elfFullName
,
3101 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
3103 lstrcpynW(pelf
->elfStyle
,
3104 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
3107 HeapFree(GetProcessHeap(), 0, potm
);
3109 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3111 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3112 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
3113 pelf
->elfStyle
[0] = '\0';
3116 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3121 /*************************************************************
3125 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3129 struct list
*family_elem_ptr
, *face_elem_ptr
;
3131 NEWTEXTMETRICEXW ntm
;
3132 DWORD type
, ret
= 1;
3138 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3140 if(plf
->lfFaceName
[0]) {
3142 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3145 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3146 debugstr_w(psub
->to
.name
));
3147 memcpy(&lf
, plf
, sizeof(lf
));
3148 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3152 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3153 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3154 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3155 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3156 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3157 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3158 for(i
= 0; i
< 32; i
++) {
3159 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3160 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3161 strcpyW(elf
.elfScript
, OEM_DOSW
);
3162 i
= 32; /* break out of loop */
3163 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3166 fs
.fsCsb
[0] = 1L << i
;
3168 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3170 csi
.ciCharset
= DEFAULT_CHARSET
;
3171 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3172 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3173 elf
.elfLogFont
.lfCharSet
=
3174 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3176 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3178 FIXME("Unknown elfscript for bit %d\n", i
);
3181 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3182 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3183 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3184 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3185 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3186 ntm
.ntmTm
.ntmFlags
);
3187 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3194 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3195 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3196 face_elem_ptr
= list_head(&family
->faces
);
3197 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3198 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3199 for(i
= 0; i
< 32; i
++) {
3200 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3201 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3202 strcpyW(elf
.elfScript
, OEM_DOSW
);
3203 i
= 32; /* break out of loop */
3204 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3207 fs
.fsCsb
[0] = 1L << i
;
3209 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3211 csi
.ciCharset
= DEFAULT_CHARSET
;
3212 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3213 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3214 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3217 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3219 FIXME("Unknown elfscript for bit %d\n", i
);
3222 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3223 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3224 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3225 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3226 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3227 ntm
.ntmTm
.ntmFlags
);
3228 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3237 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3239 pt
->x
.value
= vec
->x
>> 6;
3240 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3241 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3242 pt
->y
.value
= vec
->y
>> 6;
3243 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3244 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3248 /***************************************************
3249 * According to the MSDN documentation on WideCharToMultiByte,
3250 * certain codepages cannot set the default_used parameter.
3251 * This returns TRUE if the codepage can set that parameter, false else
3252 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3254 static BOOL
codepage_sets_default_used(UINT codepage
)
3267 static FT_UInt
get_glyph_index(GdiFont
*font
, UINT glyph
)
3269 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
3270 WCHAR wc
= (WCHAR
)glyph
;
3272 BOOL
*default_used_pointer
;
3275 default_used_pointer
= NULL
;
3276 default_used
= FALSE
;
3277 if (codepage_sets_default_used(font
->codepage
))
3278 default_used_pointer
= &default_used
;
3279 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
3282 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
3283 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
3287 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
3288 glyph
= glyph
+ 0xf000;
3289 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
3292 /*************************************************************
3293 * WineEngGetGlyphIndices
3295 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3297 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
3298 LPWORD pgi
, DWORD flags
)
3301 WCHAR default_char
= 0;
3304 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0x001f; /* Indicate non existence */
3306 for(i
= 0; i
< count
; i
++)
3308 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
3313 WineEngGetTextMetrics(font
, &textm
);
3314 default_char
= textm
.tmDefaultChar
;
3316 pgi
[i
] = default_char
;
3322 /*************************************************************
3323 * WineEngGetGlyphOutline
3325 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3326 * except that the first parameter is the HWINEENGFONT of the font in
3327 * question rather than an HDC.
3330 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
3331 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3334 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
3335 FT_Face ft_face
= incoming_font
->ft_face
;
3336 GdiFont
*font
= incoming_font
;
3337 FT_UInt glyph_index
;
3338 DWORD width
, height
, pitch
, needed
= 0;
3339 FT_Bitmap ft_bitmap
;
3341 INT left
, right
, top
= 0, bottom
= 0;
3343 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3344 float widthRatio
= 1.0;
3345 FT_Matrix transMat
= identityMat
;
3346 BOOL needsTransform
= FALSE
;
3349 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
3350 buflen
, buf
, lpmat
);
3352 if(format
& GGO_GLYPH_INDEX
) {
3353 glyph_index
= glyph
;
3354 format
&= ~GGO_GLYPH_INDEX
;
3356 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
3357 ft_face
= font
->ft_face
;
3360 if(glyph_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
3361 font
->gmsize
= (glyph_index
/ GM_BLOCK_SIZE
+ 1);
3362 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
3363 font
->gmsize
* sizeof(GM
*));
3365 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] != NULL
&& FONT_GM(font
,glyph_index
)->init
) {
3366 *lpgm
= FONT_GM(font
,glyph_index
)->gm
;
3367 return 1; /* FIXME */
3371 if (!font
->gm
[glyph_index
/ GM_BLOCK_SIZE
])
3372 font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3374 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
3375 load_flags
|= FT_LOAD_NO_BITMAP
;
3377 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
3380 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
3384 /* Scaling factor */
3385 if (font
->aveWidth
&& font
->potm
) {
3386 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
3389 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
3390 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
3392 FONT_GM(font
,glyph_index
)->adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
3393 FONT_GM(font
,glyph_index
)->lsb
= left
>> 6;
3394 FONT_GM(font
,glyph_index
)->bbx
= (right
- left
) >> 6;
3396 /* Scaling transform */
3397 if(font
->aveWidth
) {
3399 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
3402 scaleMat
.yy
= (1 << 16);
3404 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
3405 needsTransform
= TRUE
;
3408 /* Slant transform */
3409 if (font
->fake_italic
) {
3412 slantMat
.xx
= (1 << 16);
3413 slantMat
.xy
= ((1 << 16) >> 2);
3415 slantMat
.yy
= (1 << 16);
3416 pFT_Matrix_Multiply(&slantMat
, &transMat
);
3417 needsTransform
= TRUE
;
3420 /* Rotation transform */
3421 if(font
->orientation
) {
3422 FT_Matrix rotationMat
;
3424 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
3425 pFT_Vector_Unit(&vecAngle
, angle
);
3426 rotationMat
.xx
= vecAngle
.x
;
3427 rotationMat
.xy
= -vecAngle
.y
;
3428 rotationMat
.yx
= -rotationMat
.xy
;
3429 rotationMat
.yy
= rotationMat
.xx
;
3431 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
3432 needsTransform
= TRUE
;
3435 /* Extra transformation specified by caller */
3438 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
3439 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
3440 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
3441 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
3442 pFT_Matrix_Multiply(&extraMat
, &transMat
);
3443 needsTransform
= TRUE
;
3446 if(!needsTransform
) {
3447 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
3448 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
3449 ft_face
->glyph
->metrics
.height
) & -64;
3450 lpgm
->gmCellIncX
= FONT_GM(font
,glyph_index
)->adv
;
3451 lpgm
->gmCellIncY
= 0;
3455 for(xc
= 0; xc
< 2; xc
++) {
3456 for(yc
= 0; yc
< 2; yc
++) {
3457 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
3458 xc
* ft_face
->glyph
->metrics
.width
);
3459 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
3460 yc
* ft_face
->glyph
->metrics
.height
;
3461 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
3462 pFT_Vector_Transform(&vec
, &transMat
);
3463 if(xc
== 0 && yc
== 0) {
3464 left
= right
= vec
.x
;
3465 top
= bottom
= vec
.y
;
3467 if(vec
.x
< left
) left
= vec
.x
;
3468 else if(vec
.x
> right
) right
= vec
.x
;
3469 if(vec
.y
< bottom
) bottom
= vec
.y
;
3470 else if(vec
.y
> top
) top
= vec
.y
;
3475 right
= (right
+ 63) & -64;
3476 bottom
= bottom
& -64;
3477 top
= (top
+ 63) & -64;
3479 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
3480 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
3482 pFT_Vector_Transform(&vec
, &transMat
);
3483 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
3484 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
3486 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
3487 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
3488 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
3489 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
3491 FONT_GM(font
,glyph_index
)->gm
= *lpgm
;
3492 FONT_GM(font
,glyph_index
)->init
= TRUE
;
3494 if(format
== GGO_METRICS
)
3495 return 1; /* FIXME */
3497 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
3498 TRACE("loaded a bitmap\n");
3504 width
= lpgm
->gmBlackBoxX
;
3505 height
= lpgm
->gmBlackBoxY
;
3506 pitch
= ((width
+ 31) >> 5) << 2;
3507 needed
= pitch
* height
;
3509 if(!buf
|| !buflen
) break;
3511 switch(ft_face
->glyph
->format
) {
3512 case ft_glyph_format_bitmap
:
3514 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3515 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
3516 INT h
= ft_face
->glyph
->bitmap
.rows
;
3518 memcpy(dst
, src
, w
);
3519 src
+= ft_face
->glyph
->bitmap
.pitch
;
3525 case ft_glyph_format_outline
:
3526 ft_bitmap
.width
= width
;
3527 ft_bitmap
.rows
= height
;
3528 ft_bitmap
.pitch
= pitch
;
3529 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
3530 ft_bitmap
.buffer
= buf
;
3532 if(needsTransform
) {
3533 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3536 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3538 /* Note: FreeType will only set 'black' bits for us. */
3539 memset(buf
, 0, needed
);
3540 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3544 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3549 case GGO_GRAY2_BITMAP
:
3550 case GGO_GRAY4_BITMAP
:
3551 case GGO_GRAY8_BITMAP
:
3552 case WINE_GGO_GRAY16_BITMAP
:
3554 unsigned int mult
, row
, col
;
3557 width
= lpgm
->gmBlackBoxX
;
3558 height
= lpgm
->gmBlackBoxY
;
3559 pitch
= (width
+ 3) / 4 * 4;
3560 needed
= pitch
* height
;
3562 if(!buf
|| !buflen
) break;
3563 ft_bitmap
.width
= width
;
3564 ft_bitmap
.rows
= height
;
3565 ft_bitmap
.pitch
= pitch
;
3566 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
3567 ft_bitmap
.buffer
= buf
;
3569 if(needsTransform
) {
3570 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3573 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3575 memset(ft_bitmap
.buffer
, 0, buflen
);
3577 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3579 if(format
== GGO_GRAY2_BITMAP
)
3581 else if(format
== GGO_GRAY4_BITMAP
)
3583 else if(format
== GGO_GRAY8_BITMAP
)
3585 else if(format
== WINE_GGO_GRAY16_BITMAP
)
3593 for(row
= 0; row
< height
; row
++) {
3595 for(col
= 0; col
< width
; col
++, ptr
++) {
3596 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
3605 int contour
, point
= 0, first_pt
;
3606 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3607 TTPOLYGONHEADER
*pph
;
3609 DWORD pph_start
, cpfx
, type
;
3611 if(buflen
== 0) buf
= NULL
;
3613 if (needsTransform
&& buf
) {
3614 pFT_Outline_Transform(outline
, &transMat
);
3617 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3619 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3622 pph
->dwType
= TT_POLYGON_TYPE
;
3623 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3625 needed
+= sizeof(*pph
);
3627 while(point
<= outline
->contours
[contour
]) {
3628 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3629 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3630 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3634 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3637 } while(point
<= outline
->contours
[contour
] &&
3638 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3639 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3640 /* At the end of a contour Windows adds the start point, but
3642 if(point
> outline
->contours
[contour
] &&
3643 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3645 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3647 } else if(point
<= outline
->contours
[contour
] &&
3648 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3649 /* add closing pt for bezier */
3651 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3659 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3662 pph
->cb
= needed
- pph_start
;
3668 /* Convert the quadratic Beziers to cubic Beziers.
3669 The parametric eqn for a cubic Bezier is, from PLRM:
3670 r(t) = at^3 + bt^2 + ct + r0
3671 with the control points:
3676 A quadratic Beizer has the form:
3677 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3679 So equating powers of t leads to:
3680 r1 = 2/3 p1 + 1/3 p0
3681 r2 = 2/3 p1 + 1/3 p2
3682 and of course r0 = p0, r3 = p2
3685 int contour
, point
= 0, first_pt
;
3686 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3687 TTPOLYGONHEADER
*pph
;
3689 DWORD pph_start
, cpfx
, type
;
3690 FT_Vector cubic_control
[4];
3691 if(buflen
== 0) buf
= NULL
;
3693 if (needsTransform
&& buf
) {
3694 pFT_Outline_Transform(outline
, &transMat
);
3697 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3699 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3702 pph
->dwType
= TT_POLYGON_TYPE
;
3703 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3705 needed
+= sizeof(*pph
);
3707 while(point
<= outline
->contours
[contour
]) {
3708 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3709 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3710 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3713 if(type
== TT_PRIM_LINE
) {
3715 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3719 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3722 /* FIXME: Possible optimization in endpoint calculation
3723 if there are two consecutive curves */
3724 cubic_control
[0] = outline
->points
[point
-1];
3725 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3726 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3727 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3728 cubic_control
[0].x
>>= 1;
3729 cubic_control
[0].y
>>= 1;
3731 if(point
+1 > outline
->contours
[contour
])
3732 cubic_control
[3] = outline
->points
[first_pt
];
3734 cubic_control
[3] = outline
->points
[point
+1];
3735 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
3736 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3737 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3738 cubic_control
[3].x
>>= 1;
3739 cubic_control
[3].y
>>= 1;
3742 /* r1 = 1/3 p0 + 2/3 p1
3743 r2 = 1/3 p2 + 2/3 p1 */
3744 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3745 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3746 cubic_control
[2] = cubic_control
[1];
3747 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3748 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3749 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3750 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3752 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3753 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3754 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3759 } while(point
<= outline
->contours
[contour
] &&
3760 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3761 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3762 /* At the end of a contour Windows adds the start point,
3763 but only for Beziers and we've already done that.
3765 if(point
<= outline
->contours
[contour
] &&
3766 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3767 /* This is the closing pt of a bezier, but we've already
3768 added it, so just inc point and carry on */
3775 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3778 pph
->cb
= needed
- pph_start
;
3784 FIXME("Unsupported format %d\n", format
);
3790 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
3792 FT_Face ft_face
= font
->ft_face
;
3793 #ifdef HAVE_FREETYPE_FTWINFNT_H
3794 FT_WinFNT_HeaderRec winfnt_header
;
3796 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
3797 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3798 font
->potm
->otmSize
= size
;
3800 #define TM font->potm->otmTextMetrics
3801 #ifdef HAVE_FREETYPE_FTWINFNT_H
3802 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3804 TM
.tmHeight
= winfnt_header
.pixel_height
;
3805 TM
.tmAscent
= winfnt_header
.ascent
;
3806 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3807 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3808 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3809 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3810 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3811 TM
.tmWeight
= winfnt_header
.weight
;
3813 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3814 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3815 TM
.tmFirstChar
= winfnt_header
.first_char
;
3816 TM
.tmLastChar
= winfnt_header
.last_char
;
3817 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3818 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3819 TM
.tmItalic
= winfnt_header
.italic
;
3820 TM
.tmUnderlined
= font
->underline
;
3821 TM
.tmStruckOut
= font
->strikeout
;
3822 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3823 TM
.tmCharSet
= winfnt_header
.charset
;
3828 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3829 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3830 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3831 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3832 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3833 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3834 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3835 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3837 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3838 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3840 TM
.tmLastChar
= 255;
3841 TM
.tmDefaultChar
= 32;
3842 TM
.tmBreakChar
= 32;
3843 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3844 TM
.tmUnderlined
= font
->underline
;
3845 TM
.tmStruckOut
= font
->strikeout
;
3846 /* NB inverted meaning of TMPF_FIXED_PITCH */
3847 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
3848 TM
.tmCharSet
= font
->charset
;
3855 /*************************************************************
3856 * WineEngGetTextMetrics
3859 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
3862 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3863 if(!get_bitmap_text_metrics(font
))
3866 if(!font
->potm
) return FALSE
;
3867 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
3869 if (font
->aveWidth
) {
3870 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
3876 /*************************************************************
3877 * WineEngGetOutlineTextMetrics
3880 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
3881 OUTLINETEXTMETRICW
*potm
)
3883 FT_Face ft_face
= font
->ft_face
;
3884 UINT needed
, lenfam
, lensty
, ret
;
3886 TT_HoriHeader
*pHori
;
3887 TT_Postscript
*pPost
;
3888 FT_Fixed x_scale
, y_scale
;
3889 WCHAR
*family_nameW
, *style_nameW
;
3890 static const WCHAR spaceW
[] = {' ', '\0'};
3892 INT ascent
, descent
;
3894 TRACE("font=%p\n", font
);
3896 if(!FT_IS_SCALABLE(ft_face
))
3900 if(cbSize
>= font
->potm
->otmSize
)
3901 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
3902 return font
->potm
->otmSize
;
3906 needed
= sizeof(*potm
);
3908 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
3909 family_nameW
= strdupW(font
->name
);
3911 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
3913 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
3914 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
3915 style_nameW
, lensty
/sizeof(WCHAR
));
3917 /* These names should be read from the TT name table */
3919 /* length of otmpFamilyName */
3922 /* length of otmpFaceName */
3923 if(!strcasecmp(ft_face
->style_name
, "regular")) {
3924 needed
+= lenfam
; /* just the family name */
3926 needed
+= lenfam
+ lensty
; /* family + " " + style */
3929 /* length of otmpStyleName */
3932 /* length of otmpFullName */
3933 needed
+= lenfam
+ lensty
;
3936 x_scale
= ft_face
->size
->metrics
.x_scale
;
3937 y_scale
= ft_face
->size
->metrics
.y_scale
;
3939 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3941 FIXME("Can't find OS/2 table - not TT font?\n");
3946 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3948 FIXME("Can't find HHEA table - not TT font?\n");
3953 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3955 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",
3956 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3957 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3958 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3959 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3960 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3962 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
3963 font
->potm
->otmSize
= needed
;
3965 #define TM font->potm->otmTextMetrics
3967 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
3968 ascent
= pHori
->Ascender
;
3969 descent
= -pHori
->Descender
;
3971 ascent
= pOS2
->usWinAscent
;
3972 descent
= pOS2
->usWinDescent
;
3976 TM
.tmAscent
= font
->yMax
;
3977 TM
.tmDescent
= -font
->yMin
;
3978 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
3980 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
3981 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
3982 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
3983 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
3986 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3989 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3991 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
3992 ((ascent
+ descent
) -
3993 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
3995 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
3996 if (TM
.tmAveCharWidth
== 0) {
3997 TM
.tmAveCharWidth
= 1;
3999 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4000 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4002 TM
.tmDigitizedAspectX
= 300;
4003 TM
.tmDigitizedAspectY
= 300;
4004 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4005 * symbol range to 0 - f0ff
4007 if (font
->charset
== SYMBOL_CHARSET
)
4010 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4011 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4012 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4013 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4014 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4015 TM
.tmUnderlined
= font
->underline
;
4016 TM
.tmStruckOut
= font
->strikeout
;
4018 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4019 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4020 (pOS2
->version
== 0xFFFFU
||
4021 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4022 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4024 TM
.tmPitchAndFamily
= 0;
4026 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4027 case PAN_FAMILY_SCRIPT
:
4028 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4030 case PAN_FAMILY_DECORATIVE
:
4031 case PAN_FAMILY_PICTORIAL
:
4032 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4034 case PAN_FAMILY_TEXT_DISPLAY
:
4035 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4036 TM
.tmPitchAndFamily
= FF_MODERN
;
4038 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4039 case PAN_SERIF_NORMAL_SANS
:
4040 case PAN_SERIF_OBTUSE_SANS
:
4041 case PAN_SERIF_PERP_SANS
:
4042 TM
.tmPitchAndFamily
|= FF_SWISS
;
4045 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4050 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4053 if(FT_IS_SCALABLE(ft_face
))
4054 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4055 if(FT_IS_SFNT(ft_face
))
4056 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4058 TM
.tmCharSet
= font
->charset
;
4061 font
->potm
->otmFiller
= 0;
4062 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4063 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4064 font
->potm
->otmfsType
= pOS2
->fsType
;
4065 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4066 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4067 font
->potm
->otmItalicAngle
= 0; /* POST table */
4068 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4069 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4070 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4071 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4072 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4073 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
4074 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4075 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
4076 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
4077 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
4078 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
4079 font
->potm
->otmMacDescent
= 0;
4080 font
->potm
->otmMacLineGap
= 0;
4081 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
4082 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
4083 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
4084 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
4085 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
4086 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
4087 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
4088 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
4089 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
4090 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
4091 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
4093 font
->potm
->otmsUnderscoreSize
= 0;
4094 font
->potm
->otmsUnderscorePosition
= 0;
4096 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
4097 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
4100 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4101 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
4102 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
4103 strcpyW((WCHAR
*)cp
, family_nameW
);
4105 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
4106 strcpyW((WCHAR
*)cp
, style_nameW
);
4108 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
4109 strcpyW((WCHAR
*)cp
, family_nameW
);
4110 if(strcasecmp(ft_face
->style_name
, "regular")) {
4111 strcatW((WCHAR
*)cp
, spaceW
);
4112 strcatW((WCHAR
*)cp
, style_nameW
);
4113 cp
+= lenfam
+ lensty
;
4116 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
4117 strcpyW((WCHAR
*)cp
, family_nameW
);
4118 strcatW((WCHAR
*)cp
, spaceW
);
4119 strcatW((WCHAR
*)cp
, style_nameW
);
4122 if(potm
&& needed
<= cbSize
)
4123 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4126 HeapFree(GetProcessHeap(), 0, style_nameW
);
4127 HeapFree(GetProcessHeap(), 0, family_nameW
);
4132 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
4134 HFONTLIST
*hfontlist
;
4135 child
->font
= alloc_font();
4136 child
->font
->ft_face
= OpenFontFile(child
->font
, child
->face
->file
, child
->face
->face_index
, 0, -font
->ppem
);
4137 if(!child
->font
->ft_face
)
4139 free_font(child
->font
);
4144 child
->font
->orientation
= font
->orientation
;
4145 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
4146 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
4147 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
4148 child
->font
->base_font
= font
;
4149 list_add_head(&child_font_list
, &child
->font
->entry
);
4150 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
4154 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
4157 CHILD_FONT
*child_font
;
4160 font
= font
->base_font
;
4162 *linked_font
= font
;
4164 if((*glyph
= get_glyph_index(font
, c
)))
4167 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
4169 if(!child_font
->font
)
4170 if(!load_child_font(font
, child_font
))
4173 if(!child_font
->font
->ft_face
)
4175 g
= get_glyph_index(child_font
->font
, c
);
4179 *linked_font
= child_font
->font
;
4186 /*************************************************************
4187 * WineEngGetCharWidth
4190 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4195 FT_UInt glyph_index
;
4196 GdiFont
*linked_font
;
4198 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4200 for(c
= firstChar
; c
<= lastChar
; c
++) {
4201 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4202 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4203 &gm
, 0, NULL
, NULL
);
4204 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
4209 /*************************************************************
4210 * WineEngGetCharABCWidths
4213 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4218 FT_UInt glyph_index
;
4219 GdiFont
*linked_font
;
4221 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4223 if(!FT_IS_SCALABLE(font
->ft_face
))
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
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
4231 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
4232 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
4233 FONT_GM(linked_font
,glyph_index
)->bbx
;
4238 /*************************************************************
4239 * WineEngGetCharABCWidthsI
4242 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4247 FT_UInt glyph_index
;
4248 GdiFont
*linked_font
;
4250 if(!FT_IS_SCALABLE(font
->ft_face
))
4253 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
4255 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
4256 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4257 &gm
, 0, NULL
, NULL
);
4258 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
4259 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
4260 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
4261 - FONT_GM(linked_font
,c
)->bbx
;
4264 for(c
= 0; c
< count
; c
++) {
4265 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4266 &gm
, 0, NULL
, NULL
);
4267 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
4268 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
4269 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
4270 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
4276 /*************************************************************
4277 * WineEngGetTextExtentExPoint
4280 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4281 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4287 FT_UInt glyph_index
;
4288 GdiFont
*linked_font
;
4290 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
4294 WineEngGetTextMetrics(font
, &tm
);
4295 size
->cy
= tm
.tmHeight
;
4297 for(idx
= 0; idx
< count
; idx
++) {
4298 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
4299 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4300 &gm
, 0, NULL
, NULL
);
4301 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
4303 if (! pnfit
|| ext
<= max_ext
) {
4313 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4317 /*************************************************************
4318 * WineEngGetTextExtentPointI
4321 BOOL
WineEngGetTextExtentPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4328 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
4331 WineEngGetTextMetrics(font
, &tm
);
4332 size
->cy
= tm
.tmHeight
;
4334 for(idx
= 0; idx
< count
; idx
++) {
4335 WineEngGetGlyphOutline(font
, indices
[idx
],
4336 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
4338 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
4340 TRACE("return %d,%d\n", size
->cx
, size
->cy
);
4344 /*************************************************************
4345 * WineEngGetFontData
4348 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4351 FT_Face ft_face
= font
->ft_face
;
4355 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4356 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
4357 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
4359 if(!FT_IS_SFNT(ft_face
))
4367 if(table
) { /* MS tags differ in endidness from FT ones */
4368 table
= table
>> 24 | table
<< 24 |
4369 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
4372 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4373 if(pFT_Load_Sfnt_Table
) {
4374 /* make sure value of len is the value freetype says it needs */
4376 FT_ULong needed
= 0;
4377 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4378 if( !err
&& needed
< len
) len
= needed
;
4380 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4382 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4383 else { /* Do it the hard way */
4384 TT_Face tt_face
= (TT_Face
) ft_face
;
4385 SFNT_Interface
*sfnt
;
4386 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
4389 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
4393 /* A field was added in the middle of the structure in 2.1.x */
4394 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
4396 /* make sure value of len is the value freetype says it needs */
4398 FT_ULong needed
= 0;
4399 err
= sfnt
->load_any(tt_face
, table
, offset
, NULL
, &needed
);
4400 if( !err
&& needed
< len
) len
= needed
;
4402 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
4408 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4409 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4410 "Please upgrade your freetype library.\n");
4413 err
= FT_Err_Unimplemented_Feature
;
4417 TRACE("Can't find table %c%c%c%c\n",
4418 /* bytes were reversed */
4419 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4420 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4426 /*************************************************************
4427 * WineEngGetTextFace
4430 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4433 lstrcpynW(str
, font
->name
, count
);
4434 return strlenW(font
->name
);
4436 return strlenW(font
->name
) + 1;
4439 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4441 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
4442 return font
->charset
;
4445 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4447 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
4448 struct list
*first_hfont
;
4451 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
4452 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
4453 if(font
== linked_font
)
4454 *new_hfont
= dc
->hFont
;
4457 first_hfont
= list_head(&linked_font
->hfontlist
);
4458 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
4464 /* Retrieve a list of supported Unicode ranges for a given font.
4465 * Can be called with NULL gs to calculate the buffer size. Returns
4466 * the number of ranges found.
4468 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
4470 DWORD num_ranges
= 0;
4472 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4475 FT_ULong char_code
, char_code_prev
;
4478 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
4480 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4481 face
->num_glyphs
, glyph_code
, char_code
);
4483 if (!glyph_code
) return 0;
4487 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4488 gs
->ranges
[0].cGlyphs
= 0;
4489 gs
->cGlyphsSupported
= 0;
4495 if (char_code
< char_code_prev
)
4497 ERR("expected increasing char code from FT_Get_Next_Char\n");
4500 if (char_code
- char_code_prev
> 1)
4505 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4506 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4507 gs
->cGlyphsSupported
++;
4512 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4513 gs
->cGlyphsSupported
++;
4515 char_code_prev
= char_code
;
4516 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
4520 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
4525 DWORD
WineEngGetFontUnicodeRanges(HDC hdc
, LPGLYPHSET glyphset
)
4528 DC
*dc
= DC_GetDCPtr(hdc
);
4530 TRACE("(%p, %p)\n", hdc
, glyphset
);
4536 DWORD num_ranges
= get_font_unicode_ranges(dc
->gdiFont
->ft_face
, glyphset
);
4538 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
4541 glyphset
->cbThis
= size
;
4542 glyphset
->cRanges
= num_ranges
;
4546 DC_ReleaseDCPtr(dc
);
4550 /*************************************************************
4553 BOOL WINAPI
FontIsLinked(HDC hdc
)
4555 DC
*dc
= DC_GetDCPtr(hdc
);
4558 if(!dc
) return FALSE
;
4559 if(dc
->gdiFont
&& !list_empty(&dc
->gdiFont
->child_fonts
))
4561 DC_ReleaseDCPtr(dc
);
4562 TRACE("returning %d\n", ret
);
4566 static BOOL
is_hinting_enabled(void)
4568 /* Use the >= 2.2.0 function if available */
4569 if(pFT_Get_TrueType_Engine_Type
)
4571 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
4572 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
4574 #ifdef FT_DRIVER_HAS_HINTER
4579 /* otherwise if we've been compiled with < 2.2.0 headers
4580 use the internal macro */
4581 mod
= pFT_Get_Module(library
, "truetype");
4582 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
4590 /*************************************************************************
4591 * GetRasterizerCaps (GDI32.@)
4593 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
4595 static int hinting
= -1;
4599 hinting
= is_hinting_enabled();
4600 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
4603 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
4604 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
4605 lprs
->nLanguageID
= 0;
4609 /*************************************************************************
4610 * Kerning support for TrueType fonts
4612 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4614 struct TT_kern_table
4620 struct TT_kern_subtable
4629 USHORT horizontal
: 1;
4631 USHORT cross_stream
: 1;
4632 USHORT override
: 1;
4633 USHORT reserved1
: 4;
4639 struct TT_format0_kern_subtable
4643 USHORT entrySelector
;
4654 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
4655 const struct TT_format0_kern_subtable
*tt_f0_ks
,
4656 const USHORT
*glyph_to_char
,
4657 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
4660 const struct TT_kern_pair
*tt_kern_pair
;
4662 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
4664 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
4666 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4667 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
4668 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
4670 if (!kern_pair
|| !cPairs
)
4673 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
4675 nPairs
= min(nPairs
, cPairs
);
4677 for (i
= 0; i
< nPairs
; i
++)
4679 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
4680 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
4681 /* this algorithm appears to better match what Windows does */
4682 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
4683 if (kern_pair
->iKernAmount
< 0)
4685 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
4686 kern_pair
->iKernAmount
-= font
->ppem
;
4688 else if (kern_pair
->iKernAmount
> 0)
4690 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
4691 kern_pair
->iKernAmount
+= font
->ppem
;
4693 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
4695 TRACE("left %u right %u value %d\n",
4696 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
4700 TRACE("copied %u entries\n", nPairs
);
4704 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
4708 const struct TT_kern_table
*tt_kern_table
;
4709 const struct TT_kern_subtable
*tt_kern_subtable
;
4711 USHORT
*glyph_to_char
;
4713 if (font
->total_kern_pairs
!= (DWORD
)-1)
4715 if (cPairs
&& kern_pair
)
4717 cPairs
= min(cPairs
, font
->total_kern_pairs
);
4718 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
4721 return font
->total_kern_pairs
;
4724 font
->total_kern_pairs
= 0;
4726 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
4728 if (length
== GDI_ERROR
)
4730 TRACE("no kerning data in the font\n");
4734 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
4737 WARN("Out of memory\n");
4741 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
4743 /* build a glyph index to char code map */
4744 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
4747 WARN("Out of memory allocating a glyph index to char code map\n");
4748 HeapFree(GetProcessHeap(), 0, buf
);
4752 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4758 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
4760 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4761 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
4765 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4767 /* FIXME: This doesn't match what Windows does: it does some fancy
4768 * things with duplicate glyph index to char code mappings, while
4769 * we just avoid overriding existing entries.
4771 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
4772 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
4774 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
4781 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
4782 for (n
= 0; n
<= 65535; n
++)
4783 glyph_to_char
[n
] = (USHORT
)n
;
4786 tt_kern_table
= buf
;
4787 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
4788 TRACE("version %u, nTables %u\n",
4789 GET_BE_WORD(tt_kern_table
->version
), nTables
);
4791 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
4793 for (i
= 0; i
< nTables
; i
++)
4795 struct TT_kern_subtable tt_kern_subtable_copy
;
4797 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
4798 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
4799 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
4801 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4802 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
4803 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
4805 /* According to the TrueType specification this is the only format
4806 * that will be properly interpreted by Windows and OS/2
4808 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
4810 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
4812 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4813 glyph_to_char
, NULL
, 0);
4814 font
->total_kern_pairs
+= new_chunk
;
4816 if (!font
->kern_pairs
)
4817 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
4818 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
4820 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
4821 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
4823 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4824 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
4827 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
4829 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
4832 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
4833 HeapFree(GetProcessHeap(), 0, buf
);
4835 if (cPairs
&& kern_pair
)
4837 cPairs
= min(cPairs
, font
->total_kern_pairs
);
4838 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
4841 return font
->total_kern_pairs
;
4844 #else /* HAVE_FREETYPE */
4846 /*************************************************************************/
4848 BOOL
WineEngInit(void)
4852 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
4856 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
4861 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4866 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4867 LPWORD pgi
, DWORD flags
)
4872 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
4873 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4876 ERR("called but we don't have FreeType\n");
4880 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4882 ERR("called but we don't have FreeType\n");
4886 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4887 OUTLINETEXTMETRICW
*potm
)
4889 ERR("called but we don't have FreeType\n");
4893 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4896 ERR("called but we don't have FreeType\n");
4900 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4903 ERR("called but we don't have FreeType\n");
4907 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4910 ERR("called but we don't have FreeType\n");
4914 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4915 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
4917 ERR("called but we don't have FreeType\n");
4921 BOOL
WineEngGetTextExtentPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4924 ERR("called but we don't have FreeType\n");
4928 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4931 ERR("called but we don't have FreeType\n");
4935 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4937 ERR("called but we don't have FreeType\n");
4941 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
4947 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
4953 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4956 return DEFAULT_CHARSET
;
4959 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4964 DWORD
WineEngGetFontUnicodeRanges(HDC hdc
, LPGLYPHSET glyphset
)
4966 FIXME("(%p, %p): stub\n", hdc
, glyphset
);
4970 BOOL WINAPI
FontIsLinked(HDC hdc
)
4975 /*************************************************************************
4976 * GetRasterizerCaps (GDI32.@)
4978 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
4980 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
4982 lprs
->nLanguageID
= 0;
4986 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
4988 ERR("called but we don't have FreeType\n");
4992 #endif /* HAVE_FREETYPE */