2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
60 #undef GetCurrentThread
63 #undef GetCurrentProcess
76 #endif /* HAVE_CARBON_CARBON_H */
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font
);
93 #ifdef HAVE_FT2BUILD_H
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
105 #ifdef HAVE_FREETYPE_FTSNAMES_H
106 #include <freetype/ftsnames.h>
108 # ifdef HAVE_FREETYPE_FTNAMES_H
109 # include <freetype/ftnames.h>
112 #ifdef HAVE_FREETYPE_TTNAMEID_H
113 #include <freetype/ttnameid.h>
115 #ifdef HAVE_FREETYPE_FTOUTLN_H
116 #include <freetype/ftoutln.h>
118 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
119 #include <freetype/internal/sfnt.h>
121 #ifdef HAVE_FREETYPE_FTTRIGON_H
122 #include <freetype/fttrigon.h>
124 #ifdef HAVE_FREETYPE_FTWINFNT_H
125 #include <freetype/ftwinfnt.h>
127 #ifdef HAVE_FREETYPE_FTMODAPI_H
128 #include <freetype/ftmodapi.h>
131 #ifndef SONAME_LIBFREETYPE
132 #define SONAME_LIBFREETYPE "libfreetype.so"
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType
;
144 static FT_Library library
= 0;
151 static FT_Version_t FT_Version
;
152 static DWORD FT_SimpleVersion
;
154 static void *ft_handle
= NULL
;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Vector_Unit
);
158 MAKE_FUNCPTR(FT_Done_Face
);
159 MAKE_FUNCPTR(FT_Get_Char_Index
);
160 MAKE_FUNCPTR(FT_Get_Module
);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
164 MAKE_FUNCPTR(FT_Init_FreeType
);
165 MAKE_FUNCPTR(FT_Load_Glyph
);
166 MAKE_FUNCPTR(FT_Matrix_Multiply
);
167 MAKE_FUNCPTR(FT_MulFix
);
168 MAKE_FUNCPTR(FT_New_Face
);
169 MAKE_FUNCPTR(FT_New_Memory_Face
);
170 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
171 MAKE_FUNCPTR(FT_Outline_Transform
);
172 MAKE_FUNCPTR(FT_Outline_Translate
);
173 MAKE_FUNCPTR(FT_Select_Charmap
);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
175 MAKE_FUNCPTR(FT_Vector_Transform
);
176 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
177 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
178 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
179 static FT_ULong (*pFT_Get_Next_Char
)(FT_Face
,FT_ULong
,FT_UInt
*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
185 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent
);
188 MAKE_FUNCPTR(FcFontList
);
189 MAKE_FUNCPTR(FcFontSetDestroy
);
190 MAKE_FUNCPTR(FcInit
);
191 MAKE_FUNCPTR(FcObjectSetAdd
);
192 MAKE_FUNCPTR(FcObjectSetCreate
);
193 MAKE_FUNCPTR(FcObjectSetDestroy
);
194 MAKE_FUNCPTR(FcPatternCreate
);
195 MAKE_FUNCPTR(FcPatternDestroy
);
196 MAKE_FUNCPTR(FcPatternGetBool
);
197 MAKE_FUNCPTR(FcPatternGetString
);
198 #ifndef SONAME_LIBFONTCONFIG
199 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
205 #ifndef ft_encoding_none
206 #define FT_ENCODING_NONE ft_encoding_none
208 #ifndef ft_encoding_ms_symbol
209 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
211 #ifndef ft_encoding_unicode
212 #define FT_ENCODING_UNICODE ft_encoding_unicode
214 #ifndef ft_encoding_apple_roman
215 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
218 #ifdef WORDS_BIGENDIAN
219 #define GET_BE_WORD(x) (x)
221 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
224 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
231 FT_Short internal_leading
;
234 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
235 So to let this compile on older versions of FreeType we'll define the
236 new structure here. */
238 FT_Short height
, width
;
239 FT_Pos size
, x_ppem
, y_ppem
;
242 typedef struct tagFace
{
250 FONTSIGNATURE fs_links
;
251 FT_Fixed font_version
;
253 Bitmap_Size size
; /* set if face is a bitmap */
254 BOOL external
; /* TRUE if we should manually add this font to the registry */
255 struct tagFamily
*family
;
256 /* Cached data for Enum */
259 NEWTEXTMETRICEXW ntm
;
263 typedef struct tagFamily
{
265 const WCHAR
*FamilyName
;
266 const WCHAR
*EnglishName
;
272 INT adv
; /* These three hold to widths of the unrotated chars */
290 typedef struct tagHFONTLIST
{
305 struct font_mapping
*mapping
;
316 struct list hfontlist
;
321 OUTLINETEXTMETRICW
*potm
;
322 DWORD total_kern_pairs
;
323 KERNINGPAIR
*kern_pairs
;
326 struct list child_fonts
;
332 const WCHAR
*font_name
;
336 #define INIT_GM_SIZE 128
338 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
339 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
340 #define UNUSED_CACHE_SIZE 10
341 static struct list child_font_list
= LIST_INIT(child_font_list
);
342 static struct list system_links
= LIST_INIT(system_links
);
344 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
346 static struct list font_list
= LIST_INIT(font_list
);
348 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
349 static const WCHAR defSans
[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
350 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
352 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
354 static const WCHAR fontsW
[] = {'\\','F','o','n','t','s','\0'};
355 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
356 'W','i','n','d','o','w','s','\\',
357 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
358 'F','o','n','t','s','\0'};
360 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
361 'W','i','n','d','o','w','s',' ','N','T','\\',
362 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
363 'F','o','n','t','s','\0'};
365 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
366 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
367 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
368 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
370 static const WCHAR
* const SystemFontValues
[4] = {
377 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
378 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
380 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
381 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
382 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
383 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
384 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
385 'E','u','r','o','p','e','a','n','\0'};
386 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
387 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
388 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
389 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
390 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
391 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
392 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
393 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
394 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
395 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
396 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
397 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
399 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
409 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
417 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
426 typedef struct tagFontSubst
{
432 /* Registry font cache key and value names */
433 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
434 'F','o','n','t','s',0};
435 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
436 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
437 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
438 static const WCHAR face_italic_value
[] = {'I','t','a','l','i','c',0};
439 static const WCHAR face_bold_value
[] = {'B','o','l','d',0};
440 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
441 static const WCHAR face_external_value
[] = {'E','x','t','e','r','n','a','l',0};
442 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
443 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
444 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
445 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
446 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
447 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
448 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
461 static struct list mappings_list
= LIST_INIT( mappings_list
);
463 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
465 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
466 static HANDLE font_mutex
;
469 /****************************************
470 * Notes on .fon files
472 * The fonts System, FixedSys and Terminal are special. There are typically multiple
473 * versions installed for different resolutions and codepages. Windows stores which one to use
474 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
476 * FIXEDFON.FON FixedSys
478 * OEMFONT.FON Terminal
479 * LogPixels Current dpi set by the display control panel applet
480 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
481 * also has a LogPixels value that appears to mirror this)
483 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
484 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
485 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
486 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
487 * so that makes sense.
489 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
490 * to be mapped into the registry on Windows 2000 at least).
493 * ega80woa.fon=ega80850.fon
494 * ega40woa.fon=ega40850.fon
495 * cga80woa.fon=cga80850.fon
496 * cga40woa.fon=cga40850.fon
499 #ifdef HAVE_CARBON_CARBON_H
500 static char *find_cache_dir(void)
504 static char cached_path
[MAX_PATH
];
505 static const char *wine
= "/Wine", *fonts
= "/Fonts";
507 if(*cached_path
) return cached_path
;
509 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
512 WARN("can't create cached data folder\n");
515 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
518 WARN("can't create cached data path\n");
522 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
524 ERR("Could not create full path\n");
528 strcat(cached_path
, wine
);
530 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
532 WARN("Couldn't mkdir %s\n", cached_path
);
536 strcat(cached_path
, fonts
);
537 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
539 WARN("Couldn't mkdir %s\n", cached_path
);
546 /******************************************************************
549 * Extracts individual TrueType font files from a Mac suitcase font
550 * and saves them into the user's caches directory (see
552 * Returns a NULL terminated array of filenames.
554 * We do this because they are apps that try to read ttf files
555 * themselves and they don't like Mac suitcase files.
557 static char **expand_mac_font(const char *path
)
564 const char *filename
;
568 unsigned int size
, max_size
;
571 TRACE("path %s\n", path
);
573 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
576 WARN("failed to get ref\n");
580 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
583 TRACE("no data fork, so trying resource fork\n");
584 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
587 TRACE("unable to open resource fork\n");
594 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
597 CloseResFile(res_ref
);
601 out_dir
= find_cache_dir();
603 filename
= strrchr(path
, '/');
604 if(!filename
) filename
= path
;
607 /* output filename has the form out_dir/filename_%04x.ttf */
608 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
615 unsigned short *num_faces_ptr
, num_faces
, face
;
619 fond
= Get1IndResource('FOND', idx
);
621 TRACE("got fond resource %d\n", idx
);
624 fam_rec
= *(FamRec
**)fond
;
625 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
626 num_faces
= GET_BE_WORD(*num_faces_ptr
);
628 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
629 TRACE("num faces %04x\n", num_faces
);
630 for(face
= 0; face
< num_faces
; face
++, assoc
++)
633 unsigned short size
, font_id
;
636 size
= GET_BE_WORD(assoc
->fontSize
);
637 font_id
= GET_BE_WORD(assoc
->fontID
);
640 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
644 TRACE("trying to load sfnt id %04x\n", font_id
);
645 sfnt
= GetResource('sfnt', font_id
);
648 TRACE("can't get sfnt resource %04x\n", font_id
);
652 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
657 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
659 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
660 if(fd
!= -1 || errno
== EEXIST
)
664 unsigned char *sfnt_data
;
667 sfnt_data
= *(unsigned char**)sfnt
;
668 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
672 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
675 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
677 ret
.array
[ret
.size
++] = output
;
681 WARN("unable to create %s\n", output
);
682 HeapFree(GetProcessHeap(), 0, output
);
685 ReleaseResource(sfnt
);
688 ReleaseResource(fond
);
691 CloseResFile(res_ref
);
696 #endif /* HAVE_CARBON_CARBON_H */
698 static inline BOOL
is_win9x(void)
700 return GetVersion() & 0x80000000;
703 This function builds an FT_Fixed from a float. It puts the integer part
704 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
705 It fails if the integer part of the float number is greater than SHORT_MAX.
707 static inline FT_Fixed
FT_FixedFromFloat(float f
)
710 unsigned short fract
= (f
- value
) * 0xFFFF;
711 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
715 This function builds an FT_Fixed from a FIXED. It simply put f.value
716 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
718 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
720 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
724 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
729 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
730 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
732 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
733 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
735 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
737 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
739 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
741 file
= strrchr(face
->file
, '/');
746 if(!strcasecmp(file
, file_nameA
))
748 HeapFree(GetProcessHeap(), 0, file_nameA
);
753 HeapFree(GetProcessHeap(), 0, file_nameA
);
757 static Family
*find_family_from_name(const WCHAR
*name
)
761 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
763 if(!strcmpiW(family
->FamilyName
, name
))
770 static Face
*find_face_from_path_index(const CHAR
*file_name
, const INT index
)
775 TRACE("looking for file %s index %i\n", debugstr_a(file_name
), index
);
777 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
779 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
781 if(!strcasecmp(face
->file
, file_name
) && face
->face_index
== index
)
788 static void DumpSubstList(void)
792 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
794 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
795 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
796 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
798 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
799 debugstr_w(psub
->to
.name
));
804 static LPWSTR
strdupW(LPCWSTR p
)
807 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
808 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
813 static LPSTR
strdupA(LPCSTR p
)
816 DWORD len
= (strlen(p
) + 1);
817 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
822 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
827 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
829 if(!strcmpiW(element
->from
.name
, from_name
) &&
830 (element
->from
.charset
== from_charset
||
831 element
->from
.charset
== -1))
838 #define ADD_FONT_SUBST_FORCE 1
840 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
842 FontSubst
*from_exist
, *to_exist
;
844 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
846 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
848 list_remove(&from_exist
->entry
);
849 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
850 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
851 HeapFree(GetProcessHeap(), 0, from_exist
);
857 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
861 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
862 subst
->to
.name
= strdupW(to_exist
->to
.name
);
865 list_add_tail(subst_list
, &subst
->entry
);
870 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
871 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
872 HeapFree(GetProcessHeap(), 0, subst
);
876 static void split_subst_info(NameCs
*nc
, LPSTR str
)
878 CHAR
*p
= strrchr(str
, ',');
883 nc
->charset
= strtol(p
+1, NULL
, 10);
886 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
887 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
888 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
891 static void LoadSubstList(void)
895 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
899 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
900 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
901 &hkey
) == ERROR_SUCCESS
) {
903 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
904 &valuelen
, &datalen
, NULL
, NULL
);
906 valuelen
++; /* returned value doesn't include room for '\0' */
907 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
908 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
912 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
913 &dlen
) == ERROR_SUCCESS
) {
914 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
916 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
917 split_subst_info(&psub
->from
, value
);
918 split_subst_info(&psub
->to
, data
);
920 /* Win 2000 doesn't allow mapping between different charsets
921 or mapping of DEFAULT_CHARSET */
922 if((psub
->to
.charset
!= psub
->from
.charset
) ||
923 psub
->to
.charset
== DEFAULT_CHARSET
) {
924 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
925 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
926 HeapFree(GetProcessHeap(), 0, psub
);
928 add_font_subst(&font_subst_list
, psub
, 0);
930 /* reset dlen and vlen */
934 HeapFree(GetProcessHeap(), 0, data
);
935 HeapFree(GetProcessHeap(), 0, value
);
940 static WCHAR
*get_familyname(FT_Face ft_face
)
942 WCHAR
*family
= NULL
;
944 FT_UInt num_names
, name_index
, i
;
946 if(FT_IS_SFNT(ft_face
))
948 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
950 for(name_index
= 0; name_index
< num_names
; name_index
++)
952 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
954 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
955 (name
.language_id
== GetUserDefaultLCID()) &&
956 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
957 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
959 /* String is not nul terminated and string_len is a byte length. */
960 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
961 for(i
= 0; i
< name
.string_len
/ 2; i
++)
963 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
964 family
[i
] = GET_BE_WORD(*tmp
);
968 TRACE("Got localised name %s\n", debugstr_w(family
));
978 static HRESULT
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
981 HRESULT r
= RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, &needed
);
982 if(FAILED(r
)) return r
;
983 if(type
!= REG_DWORD
|| needed
!= sizeof(DWORD
)) return E_FAIL
;
984 return RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &needed
);
987 static inline HRESULT
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
989 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
992 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
)
995 DWORD num_strikes
, max_strike_key_len
;
997 /* If we have a File Name key then this is a real font, not just the parent
998 key of a bunch of non-scalable strikes */
999 if(RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1002 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1004 face
->file
= HeapAlloc(GetProcessHeap(), 0, needed
);
1005 RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, (BYTE
*)face
->file
, &needed
);
1007 face
->StyleName
= strdupW(face_name
);
1008 face
->family
= family
;
1009 face
->cache_valid
= FALSE
;
1011 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1012 reg_load_dword(hkey_face
, face_italic_value
, (DWORD
*)&face
->Italic
);
1013 reg_load_dword(hkey_face
, face_bold_value
, (DWORD
*)&face
->Bold
);
1014 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1015 reg_load_dword(hkey_face
, face_external_value
, (DWORD
*)&face
->external
);
1017 needed
= sizeof(face
->fs
);
1018 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1019 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1021 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1023 face
->scalable
= TRUE
;
1024 memset(&face
->size
, 0, sizeof(face
->size
));
1028 face
->scalable
= FALSE
;
1029 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1030 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1031 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1032 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1033 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1035 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1036 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1037 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1040 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1041 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1042 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1043 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1045 if(!face
->Italic
&& !face
->Bold
)
1046 list_add_head(&family
->faces
, &face
->entry
);
1048 list_add_tail(&family
->faces
, &face
->entry
);
1050 if(face
->fs
.fsCsb
[0] & ~(1L << 31))
1051 have_installed_roman_font
= TRUE
;
1053 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1056 /* do we have any bitmap strikes? */
1057 RegQueryInfoKeyW(hkey_face
, NULL
, NULL
, NULL
, &num_strikes
, &max_strike_key_len
, NULL
, NULL
,
1058 NULL
, NULL
, NULL
, NULL
);
1059 if(num_strikes
!= 0)
1061 WCHAR strike_name
[10];
1062 DWORD strike_index
= 0;
1064 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1065 while(RegEnumKeyExW(hkey_face
, strike_index
++, strike_name
, &needed
,
1066 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1069 RegOpenKeyExW(hkey_face
, strike_name
, 0, KEY_ALL_ACCESS
, &hkey_strike
);
1070 load_face(hkey_strike
, face_name
, family
);
1071 RegCloseKey(hkey_strike
);
1072 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1077 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1079 DWORD max_family_key_len
, size
;
1081 DWORD family_index
= 0;
1085 RegQueryInfoKeyW(hkey_font_cache
, NULL
, NULL
, NULL
, NULL
, &max_family_key_len
, NULL
, NULL
,
1086 NULL
, NULL
, NULL
, NULL
);
1087 family_name
= HeapAlloc(GetProcessHeap(), 0, (max_family_key_len
+ 1) * sizeof(WCHAR
));
1089 size
= max_family_key_len
+ 1;
1090 while(RegEnumKeyExW(hkey_font_cache
, family_index
++, family_name
, &size
,
1091 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1093 WCHAR
*english_family
= NULL
;
1094 DWORD face_index
= 0;
1096 DWORD max_face_key_len
;
1098 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1099 TRACE("opened family key %s\n", debugstr_w(family_name
));
1100 if(RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, NULL
, &size
) == ERROR_SUCCESS
)
1102 english_family
= HeapAlloc(GetProcessHeap(), 0, size
);
1103 RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)english_family
, &size
);
1106 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1107 family
->FamilyName
= strdupW(family_name
);
1108 family
->EnglishName
= english_family
;
1109 list_init(&family
->faces
);
1110 list_add_tail(&font_list
, &family
->entry
);
1114 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1115 subst
->from
.name
= strdupW(english_family
);
1116 subst
->from
.charset
= -1;
1117 subst
->to
.name
= strdupW(family_name
);
1118 subst
->to
.charset
= -1;
1119 add_font_subst(&font_subst_list
, subst
, 0);
1122 RegQueryInfoKeyW(hkey_family
, NULL
, NULL
, NULL
, NULL
, &max_face_key_len
, NULL
, NULL
,
1123 NULL
, NULL
, NULL
, NULL
);
1125 face_name
= HeapAlloc(GetProcessHeap(), 0, (max_face_key_len
+ 1) * sizeof(WCHAR
));
1126 size
= max_face_key_len
+ 1;
1127 while(RegEnumKeyExW(hkey_family
, face_index
++, face_name
, &size
,
1128 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1132 RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
);
1133 load_face(hkey_face
, face_name
, family
);
1134 RegCloseKey(hkey_face
);
1135 size
= max_face_key_len
+ 1;
1137 HeapFree(GetProcessHeap(), 0, face_name
);
1138 RegCloseKey(hkey_family
);
1139 size
= max_family_key_len
+ 1;
1142 HeapFree(GetProcessHeap(), 0, family_name
);
1146 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1149 HKEY hkey_wine_fonts
;
1151 /* We don't want to create the fonts key as volatile, so open this first */
1152 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1153 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1154 if(ret
!= ERROR_SUCCESS
)
1156 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1160 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1161 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1162 RegCloseKey(hkey_wine_fonts
);
1166 static void add_face_to_cache(Face
*face
)
1168 HKEY hkey_font_cache
, hkey_family
, hkey_face
;
1169 WCHAR
*face_key_name
;
1171 create_font_cache_key(&hkey_font_cache
, NULL
);
1173 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1174 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1175 if(face
->family
->EnglishName
)
1176 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1177 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1180 face_key_name
= face
->StyleName
;
1183 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1184 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1185 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1187 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1190 HeapFree(GetProcessHeap(), 0, face_key_name
);
1192 RegSetValueExA(hkey_face
, "File Name", 0, REG_BINARY
, (BYTE
*)face
->file
, strlen(face
->file
) + 1);
1194 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1195 reg_save_dword(hkey_face
, face_italic_value
, face
->Italic
);
1196 reg_save_dword(hkey_face
, face_bold_value
, face
->Bold
);
1197 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1198 reg_save_dword(hkey_face
, face_external_value
, face
->external
);
1200 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1204 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1205 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1206 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1207 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1208 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1209 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1211 RegCloseKey(hkey_face
);
1212 RegCloseKey(hkey_family
);
1213 RegCloseKey(hkey_font_cache
);
1216 #define ADDFONT_EXTERNAL_FONT 0x01
1217 #define ADDFONT_FORCE_BITMAP 0x02
1218 #define ADDFONT_ADD_TO_CACHE 0x04
1219 static BOOL
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1223 TT_Header
*pHeader
= NULL
;
1224 WCHAR
*english_family
, *localised_family
, *StyleW
;
1228 struct list
*family_elem_ptr
, *face_elem_ptr
;
1230 FT_Long face_index
= 0, num_faces
;
1231 #ifdef HAVE_FREETYPE_FTWINFNT_H
1232 FT_WinFNT_HeaderRec winfnt_header
;
1234 int i
, bitmap_num
, internal_leading
;
1237 #ifdef HAVE_CARBON_CARBON_H
1240 char **mac_list
= expand_mac_font(file
);
1243 BOOL had_one
= FALSE
;
1245 for(cursor
= mac_list
; *cursor
; cursor
++)
1248 AddFontFileToList(*cursor
, NULL
, NULL
, flags
);
1249 HeapFree(GetProcessHeap(), 0, *cursor
);
1251 HeapFree(GetProcessHeap(), 0, mac_list
);
1256 #endif /* HAVE_CARBON_CARBON_H */
1259 char *family_name
= fake_family
;
1261 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1262 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
1263 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
1267 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*/
1268 WARN("Ignoring font %s\n", debugstr_a(file
));
1269 pFT_Done_Face(ft_face
);
1273 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1274 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1275 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file
));
1276 pFT_Done_Face(ft_face
);
1280 if(FT_IS_SFNT(ft_face
) && (!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
1281 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1282 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))) {
1283 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1284 "Skipping this font.\n", debugstr_a(file
));
1285 pFT_Done_Face(ft_face
);
1289 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1290 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
1291 pFT_Done_Face(ft_face
);
1295 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1297 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1298 pFT_Done_Face(ft_face
);
1304 localised_family
= get_familyname(ft_face
);
1305 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1307 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1308 HeapFree(GetProcessHeap(), 0, localised_family
);
1309 num_faces
= ft_face
->num_faces
;
1310 pFT_Done_Face(ft_face
);
1313 HeapFree(GetProcessHeap(), 0, localised_family
);
1317 family_name
= ft_face
->family_name
;
1321 My_FT_Bitmap_Size
*size
= NULL
;
1323 if(!FT_IS_SCALABLE(ft_face
))
1324 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1326 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1327 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1328 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1330 localised_family
= NULL
;
1332 localised_family
= get_familyname(ft_face
);
1333 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1334 HeapFree(GetProcessHeap(), 0, localised_family
);
1335 localised_family
= NULL
;
1340 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1341 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1342 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1347 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1348 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1349 family
->EnglishName
= localised_family
? strdupW(english_family
) : NULL
;
1351 list_init(&family
->faces
);
1352 list_add_tail(&font_list
, &family
->entry
);
1354 if(localised_family
) {
1355 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1356 subst
->from
.name
= strdupW(english_family
);
1357 subst
->from
.charset
= -1;
1358 subst
->to
.name
= strdupW(localised_family
);
1359 subst
->to
.charset
= -1;
1360 add_font_subst(&font_subst_list
, subst
, 0);
1363 HeapFree(GetProcessHeap(), 0, localised_family
);
1364 HeapFree(GetProcessHeap(), 0, english_family
);
1366 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1367 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1368 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1370 internal_leading
= 0;
1371 memset(&fs
, 0, sizeof(fs
));
1373 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1375 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1376 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1377 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1378 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1379 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1380 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1381 if(pOS2
->version
== 0) {
1384 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1387 fs
.fsCsb
[0] |= 1L << 31;
1390 #ifdef HAVE_FREETYPE_FTWINFNT_H
1391 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1393 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1394 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1395 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1396 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
1397 internal_leading
= winfnt_header
.internal_leading
;
1401 face_elem_ptr
= list_head(&family
->faces
);
1402 while(face_elem_ptr
) {
1403 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1404 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1405 if(!strcmpW(face
->StyleName
, StyleW
) &&
1406 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1407 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1408 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1409 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1412 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1413 HeapFree(GetProcessHeap(), 0, StyleW
);
1414 pFT_Done_Face(ft_face
);
1417 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1418 TRACE("Original font is newer so skipping this one\n");
1419 HeapFree(GetProcessHeap(), 0, StyleW
);
1420 pFT_Done_Face(ft_face
);
1423 TRACE("Replacing original with this one\n");
1424 list_remove(&face
->entry
);
1425 HeapFree(GetProcessHeap(), 0, face
->file
);
1426 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1427 HeapFree(GetProcessHeap(), 0, face
);
1432 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1433 face
->cache_valid
= FALSE
;
1434 face
->StyleName
= StyleW
;
1435 face
->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
1436 strcpy(face
->file
, file
);
1437 face
->face_index
= face_index
;
1438 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
1439 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
1440 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1441 face
->family
= family
;
1442 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1443 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
1444 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1446 if(FT_IS_SCALABLE(ft_face
)) {
1447 memset(&face
->size
, 0, sizeof(face
->size
));
1448 face
->scalable
= TRUE
;
1450 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1451 size
->height
, size
->width
, size
->size
>> 6,
1452 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1453 face
->size
.height
= size
->height
;
1454 face
->size
.width
= size
->width
;
1455 face
->size
.size
= size
->size
;
1456 face
->size
.x_ppem
= size
->x_ppem
;
1457 face
->size
.y_ppem
= size
->y_ppem
;
1458 face
->size
.internal_leading
= internal_leading
;
1459 face
->scalable
= FALSE
;
1462 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1463 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1464 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1465 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1468 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1469 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1470 switch(ft_face
->charmaps
[i
]->encoding
) {
1471 case FT_ENCODING_UNICODE
:
1472 case FT_ENCODING_APPLE_ROMAN
:
1473 face
->fs
.fsCsb
[0] |= 1;
1475 case FT_ENCODING_MS_SYMBOL
:
1476 face
->fs
.fsCsb
[0] |= 1L << 31;
1484 if(!face
->Italic
&& !face
->Bold
)
1485 list_add_head(&family
->faces
, &face
->entry
);
1487 list_add_tail(&family
->faces
, &face
->entry
);
1489 if(flags
& ADDFONT_ADD_TO_CACHE
)
1490 add_face_to_cache(face
);
1492 if(face
->fs
.fsCsb
[0] & ~(1L << 31))
1493 have_installed_roman_font
= TRUE
;
1494 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1496 num_faces
= ft_face
->num_faces
;
1497 pFT_Done_Face(ft_face
);
1498 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1499 debugstr_w(StyleW
));
1500 } while(num_faces
> ++face_index
);
1504 static void DumpFontList(void)
1508 struct list
*family_elem_ptr
, *face_elem_ptr
;
1510 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1511 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1512 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1513 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1514 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1515 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1517 TRACE(" %d", face
->size
.height
);
1524 /***********************************************************
1525 * The replacement list is a way to map an entire font
1526 * family onto another family. For example adding
1528 * [HKCU\Software\Wine\Fonts\Replacements]
1529 * "Wingdings"="Winedings"
1531 * would enumerate the Winedings font both as Winedings and
1532 * Wingdings. However if a real Wingdings font is present the
1533 * replacement does not take place.
1536 static void LoadReplaceList(void)
1539 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1544 struct list
*family_elem_ptr
, *face_elem_ptr
;
1547 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1548 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1550 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1551 &valuelen
, &datalen
, NULL
, NULL
);
1553 valuelen
++; /* returned value doesn't include room for '\0' */
1554 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1555 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1559 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1560 &dlen
) == ERROR_SUCCESS
) {
1561 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1562 /* "NewName"="Oldname" */
1563 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1565 if(!find_family_from_name(value
))
1567 /* Find the old family and hence all of the font files
1569 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1570 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1571 if(!strcmpiW(family
->FamilyName
, data
)) {
1572 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1573 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1574 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1575 debugstr_w(face
->StyleName
), familyA
);
1576 /* Now add a new entry with the new family name */
1577 AddFontFileToList(face
->file
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1583 /* reset dlen and vlen */
1587 HeapFree(GetProcessHeap(), 0, data
);
1588 HeapFree(GetProcessHeap(), 0, value
);
1593 /*************************************************************
1596 static BOOL
init_system_links(void)
1598 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1599 'W','i','n','d','o','w','s',' ','N','T','\\',
1600 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1601 'S','y','s','t','e','m','L','i','n','k',0};
1604 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1605 WCHAR
*value
, *data
;
1606 WCHAR
*entry
, *next
;
1607 SYSTEM_LINKS
*font_link
, *system_font_link
;
1608 CHILD_FONT
*child_font
;
1609 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1610 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1611 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1617 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1619 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1620 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1621 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1622 val_len
= max_val
+ 1;
1623 data_len
= max_data
;
1625 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1627 TRACE("%s:\n", debugstr_w(value
));
1629 memset(&fs
, 0, sizeof(fs
));
1630 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1631 psub
= get_font_subst(&font_subst_list
, value
, -1);
1632 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1633 list_init(&font_link
->links
);
1634 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1637 CHILD_FONT
*child_font
;
1639 TRACE("\t%s\n", debugstr_w(entry
));
1641 next
= entry
+ strlenW(entry
) + 1;
1643 face_name
= strchrW(entry
, ',');
1647 while(isspaceW(*face_name
))
1650 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1652 face_name
= psub
->to
.name
;
1654 face
= find_face_from_filename(entry
, face_name
);
1657 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1661 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1662 child_font
->file_name
= strdupA(face
->file
);
1663 child_font
->index
= face
->face_index
;
1664 child_font
->font
= NULL
;
1665 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1666 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1667 TRACE("Adding file %s index %d\n", child_font
->file_name
, child_font
->index
);
1668 list_add_tail(&font_link
->links
, &child_font
->entry
);
1670 family
= find_family_from_name(font_link
->font_name
);
1673 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1675 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
1678 list_add_tail(&system_links
, &font_link
->entry
);
1679 val_len
= max_val
+ 1;
1680 data_len
= max_data
;
1683 HeapFree(GetProcessHeap(), 0, value
);
1684 HeapFree(GetProcessHeap(), 0, data
);
1688 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1691 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1692 system_font_link
->font_name
= strdupW(System
);
1693 list_init(&system_font_link
->links
);
1695 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1698 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1699 child_font
->file_name
= strdupA(face
->file
);
1700 child_font
->index
= face
->face_index
;
1701 child_font
->font
= NULL
;
1702 TRACE("Found Tahoma in %s index %d\n", child_font
->file_name
, child_font
->index
);
1703 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1705 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1707 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1709 CHILD_FONT
*font_link_entry
;
1710 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1712 CHILD_FONT
*new_child
;
1713 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1714 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
1715 new_child
->index
= font_link_entry
->index
;
1716 new_child
->font
= NULL
;
1717 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1722 list_add_tail(&system_links
, &system_font_link
->entry
);
1726 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1729 struct dirent
*dent
;
1730 char path
[MAX_PATH
];
1732 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1734 dir
= opendir(dirname
);
1736 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1739 while((dent
= readdir(dir
)) != NULL
) {
1740 struct stat statbuf
;
1742 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1745 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1747 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1749 if(stat(path
, &statbuf
) == -1)
1751 WARN("Can't stat %s\n", debugstr_a(path
));
1754 if(S_ISDIR(statbuf
.st_mode
))
1755 ReadFontDir(path
, external_fonts
);
1757 AddFontFileToList(path
, NULL
, NULL
, (external_fonts
? ADDFONT_EXTERNAL_FONT
: 0) | ADDFONT_ADD_TO_CACHE
);
1763 static void load_fontconfig_fonts(void)
1765 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1766 void *fc_handle
= NULL
;
1775 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1777 TRACE("Wine cannot find the fontconfig library (%s).\n",
1778 SONAME_LIBFONTCONFIG
);
1781 #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;}
1782 LOAD_FUNCPTR(FcConfigGetCurrent
);
1783 LOAD_FUNCPTR(FcFontList
);
1784 LOAD_FUNCPTR(FcFontSetDestroy
);
1785 LOAD_FUNCPTR(FcInit
);
1786 LOAD_FUNCPTR(FcObjectSetAdd
);
1787 LOAD_FUNCPTR(FcObjectSetCreate
);
1788 LOAD_FUNCPTR(FcObjectSetDestroy
);
1789 LOAD_FUNCPTR(FcPatternCreate
);
1790 LOAD_FUNCPTR(FcPatternDestroy
);
1791 LOAD_FUNCPTR(FcPatternGetBool
);
1792 LOAD_FUNCPTR(FcPatternGetString
);
1795 if(!pFcInit()) return;
1797 config
= pFcConfigGetCurrent();
1798 pat
= pFcPatternCreate();
1799 os
= pFcObjectSetCreate();
1800 pFcObjectSetAdd(os
, FC_FILE
);
1801 pFcObjectSetAdd(os
, FC_SCALABLE
);
1802 fontset
= pFcFontList(config
, pat
, os
);
1803 if(!fontset
) return;
1804 for(i
= 0; i
< fontset
->nfont
; i
++) {
1807 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1809 TRACE("fontconfig: %s\n", file
);
1811 /* We're just interested in OT/TT fonts for now, so this hack just
1812 picks up the scalable fonts without extensions .pf[ab] to save time
1813 loading every other font */
1815 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1817 TRACE("not scalable\n");
1821 len
= strlen( file
);
1822 if(len
< 4) continue;
1823 ext
= &file
[ len
- 3 ];
1824 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1825 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
1827 pFcFontSetDestroy(fontset
);
1828 pFcObjectSetDestroy(os
);
1829 pFcPatternDestroy(pat
);
1835 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1838 const char *data_dir
= wine_get_data_dir();
1840 if (!data_dir
) data_dir
= wine_get_build_dir();
1847 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1849 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1851 strcpy(unix_name
, data_dir
);
1852 strcat(unix_name
, "/fonts/");
1854 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1856 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
1857 HeapFree(GetProcessHeap(), 0, unix_name
);
1862 static void load_system_fonts(void)
1865 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1866 const WCHAR
* const *value
;
1868 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1871 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1872 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1873 strcatW(windowsdir
, fontsW
);
1874 for(value
= SystemFontValues
; *value
; value
++) {
1875 dlen
= sizeof(data
);
1876 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1880 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1881 if((unixname
= wine_get_unix_file_name(pathW
))) {
1882 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
1883 HeapFree(GetProcessHeap(), 0, unixname
);
1886 load_font_from_data_dir(data
);
1893 /*************************************************************
1895 * This adds registry entries for any externally loaded fonts
1896 * (fonts from fontconfig or FontDirs). It also deletes entries
1897 * of no longer existing fonts.
1900 static void update_reg_entries(void)
1902 HKEY winnt_key
= 0, win9x_key
, external_key
= 0;
1907 struct list
*family_elem_ptr
, *face_elem_ptr
;
1909 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1910 static const WCHAR spaceW
[] = {' ', '\0'};
1913 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1914 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1915 ERR("Can't create Windows font reg key\n");
1919 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1920 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1921 ERR("Can't create Windows font reg key\n");
1926 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1927 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1928 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
1929 ERR("Can't create external font reg key\n");
1933 /* enumerate the fonts and add external ones to the two keys */
1935 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1936 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1937 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1938 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1939 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1940 if(!face
->external
) continue;
1942 if(strcmpiW(face
->StyleName
, RegularW
))
1943 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1944 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1945 strcpyW(valueW
, family
->FamilyName
);
1946 if(len
!= len_fam
) {
1947 strcatW(valueW
, spaceW
);
1948 strcatW(valueW
, face
->StyleName
);
1950 strcatW(valueW
, TrueType
);
1952 file
= wine_get_dos_file_name(face
->file
);
1954 len
= strlenW(file
) + 1;
1957 if((path
= strrchr(face
->file
, '/')) == NULL
)
1961 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1963 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1964 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1966 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1967 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1968 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1970 HeapFree(GetProcessHeap(), 0, file
);
1971 HeapFree(GetProcessHeap(), 0, valueW
);
1975 if(external_key
) RegCloseKey(external_key
);
1976 if(win9x_key
) RegCloseKey(win9x_key
);
1977 if(winnt_key
) RegCloseKey(winnt_key
);
1981 static void delete_external_font_keys(void)
1983 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1984 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
1988 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1989 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1990 ERR("Can't create Windows font reg key\n");
1994 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1995 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1996 ERR("Can't create Windows font reg key\n");
2000 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
2001 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2002 ERR("Can't create external font reg key\n");
2006 /* Delete all external fonts added last time */
2008 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2009 &valuelen
, &datalen
, NULL
, NULL
);
2010 valuelen
++; /* returned value doesn't include room for '\0' */
2011 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2012 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2014 dlen
= datalen
* sizeof(WCHAR
);
2017 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2018 &dlen
) == ERROR_SUCCESS
) {
2020 RegDeleteValueW(winnt_key
, valueW
);
2021 RegDeleteValueW(win9x_key
, valueW
);
2022 /* reset dlen and vlen */
2026 HeapFree(GetProcessHeap(), 0, data
);
2027 HeapFree(GetProcessHeap(), 0, valueW
);
2029 /* Delete the old external fonts key */
2030 RegCloseKey(external_key
);
2031 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2034 if(win9x_key
) RegCloseKey(win9x_key
);
2035 if(winnt_key
) RegCloseKey(winnt_key
);
2038 /*************************************************************
2039 * WineEngAddFontResourceEx
2042 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2044 if (ft_handle
) /* do it only if we have freetype up and running */
2048 if((unixname
= wine_get_unix_file_name(file
)))
2050 DWORD flags
= ADDFONT_FORCE_BITMAP
;
2052 if(!(flags
& FR_PRIVATE
)) flags
|= ADDFONT_ADD_TO_CACHE
;
2053 WaitForSingleObject(font_mutex
, INFINITE
);
2054 AddFontFileToList(unixname
, NULL
, NULL
, flags
);
2055 ReleaseMutex(font_mutex
);
2056 HeapFree(GetProcessHeap(), 0, unixname
);
2062 /*************************************************************
2063 * WineEngRemoveFontResourceEx
2066 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2072 static const struct nls_update_font_list
2074 UINT ansi_cp
, oem_cp
;
2075 const char *oem
, *fixed
, *system
;
2076 const char *courier
, *serif
, *small
, *sserif
;
2077 /* these are for font substitute */
2078 const char *shelldlg
, *tmsrmn
;
2079 } nls_update_font_list
[] =
2081 /* Latin 1 (United States) */
2082 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2083 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2084 "Tahoma","Times New Roman",
2086 /* Latin 1 (Multilingual) */
2087 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2088 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2089 "Tahoma","Times New Roman", /* FIXME unverified */
2091 /* Eastern Europe */
2092 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2093 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2094 "Tahoma","Times New Roman", /* FIXME unverified */
2097 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2098 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2099 "Tahoma","Times New Roman", /* FIXME unverified */
2102 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2103 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2104 "Tahoma","Times New Roman", /* FIXME unverified */
2107 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2108 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2109 "Tahoma","Times New Roman", /* FIXME unverified */
2112 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2113 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2114 "Tahoma","Times New Roman", /* FIXME unverified */
2117 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2118 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2119 "Tahoma","Times New Roman", /* FIXME unverified */
2122 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2123 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2124 "Tahoma","Times New Roman", /* FIXME unverified */
2127 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2128 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2129 "Tahoma","Times New Roman", /* FIXME unverified */
2132 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2133 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2134 "Tahoma","Times New Roman", /* FIXME unverified */
2137 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2138 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2139 "MS UI Gothic","MS Serif",
2141 /* Chinese Simplified */
2142 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2143 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2144 "Tahoma", "Times New Roman", /* FIXME unverified */
2147 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2148 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2151 /* Chinese Traditional */
2152 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2153 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2154 "Tahoma", "Times New Roman", /* FIXME unverified */
2158 static inline HKEY
create_fonts_NT_registry_key(void)
2162 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2163 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2167 static inline HKEY
create_fonts_9x_registry_key(void)
2171 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2172 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2176 static inline HKEY
create_config_fonts_registry_key(void)
2180 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2181 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2185 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2187 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2188 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2189 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2190 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2193 static void update_font_info(void)
2195 char buf
[40], cpbuf
[40];
2198 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2200 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2203 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2204 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2205 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2206 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2207 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2210 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2212 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2217 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2219 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2221 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2224 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2226 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2227 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2231 hkey
= create_config_fonts_registry_key();
2232 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2233 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2234 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2237 hkey
= create_fonts_NT_registry_key();
2238 add_font_list(hkey
, &nls_update_font_list
[i
]);
2241 hkey
= create_fonts_9x_registry_key();
2242 add_font_list(hkey
, &nls_update_font_list
[i
]);
2245 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2247 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2248 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2249 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2250 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2256 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2259 static void init_font_list(void)
2261 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2262 static const WCHAR pathW
[] = {'P','a','t','h',0};
2264 WCHAR windowsdir
[MAX_PATH
];
2266 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2268 const char *data_dir
;
2270 /* load the system bitmap fonts */
2271 load_system_fonts();
2273 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2274 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2275 strcatW(windowsdir
, fontsW
);
2276 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2278 ReadFontDir(unixname
, FALSE
);
2279 HeapFree(GetProcessHeap(), 0, unixname
);
2282 /* load the system truetype fonts */
2283 data_dir
= wine_get_data_dir();
2284 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2285 strcpy(unixname
, data_dir
);
2286 strcat(unixname
, "/fonts/");
2287 ReadFontDir(unixname
, FALSE
);
2288 HeapFree(GetProcessHeap(), 0, unixname
);
2291 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2292 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2293 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2295 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2296 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2297 &hkey
) == ERROR_SUCCESS
) {
2299 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2300 &valuelen
, &datalen
, NULL
, NULL
);
2302 valuelen
++; /* returned value doesn't include room for '\0' */
2303 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2304 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2307 dlen
= datalen
* sizeof(WCHAR
);
2309 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2310 &dlen
) == ERROR_SUCCESS
) {
2311 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2313 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2315 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2316 HeapFree(GetProcessHeap(), 0, unixname
);
2319 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2321 WCHAR pathW
[MAX_PATH
];
2322 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2325 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2326 if((unixname
= wine_get_unix_file_name(pathW
)))
2328 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2329 HeapFree(GetProcessHeap(), 0, unixname
);
2332 load_font_from_data_dir(data
);
2334 /* reset dlen and vlen */
2339 HeapFree(GetProcessHeap(), 0, data
);
2340 HeapFree(GetProcessHeap(), 0, valueW
);
2344 load_fontconfig_fonts();
2346 /* then look in any directories that we've specified in the config file */
2347 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2348 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2354 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2356 len
+= sizeof(WCHAR
);
2357 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2358 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2360 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2361 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2362 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2363 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2367 LPSTR next
= strchr( ptr
, ':' );
2368 if (next
) *next
++ = 0;
2369 ReadFontDir( ptr
, TRUE
);
2372 HeapFree( GetProcessHeap(), 0, valueA
);
2374 HeapFree( GetProcessHeap(), 0, valueW
);
2380 static BOOL
move_to_front(const WCHAR
*name
)
2382 Family
*family
, *cursor2
;
2383 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
2385 if(!strcmpiW(family
->FamilyName
, name
))
2387 list_remove(&family
->entry
);
2388 list_add_head(&font_list
, &family
->entry
);
2395 static const WCHAR arial
[] = {'A','r','i','a','l',0};
2396 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
2397 static const WCHAR bitstream_vera_sans_mono
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
2398 static const WCHAR bitstream_vera_serif
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
2399 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
2400 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
2402 static void reorder_font_list(void)
2404 if(!move_to_front(times_new_roman
))
2405 move_to_front(bitstream_vera_serif
);
2407 if(!move_to_front(courier_new
))
2408 move_to_front(bitstream_vera_sans_mono
);
2410 if(!move_to_front(arial
))
2411 move_to_front(bitstream_vera_sans
);
2415 /*************************************************************
2418 * Initialize FreeType library and create a list of available faces
2420 BOOL
WineEngInit(void)
2422 static const WCHAR cx_hack_var
[] = {'C','X','_','T','U','R','N','_','O','F','F','_','F','O','N','T','_',
2423 'R','E','P','L','A','C','E','M','E','N','T','S',0};
2425 HKEY hkey_font_cache
;
2427 const char *ftname
= "libcxfreetype.so";
2428 char freetypelib
[MAX_PATH
];
2433 /* check if the config file specifies a freetype library */
2434 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2435 r
= RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts",
2437 if( r
== ERROR_SUCCESS
)
2439 vlen
= sizeof freetypelib
;
2440 r
= RegQueryValueExA( hkey
, "FreeTypeLib", 0, &type
,
2441 (LPBYTE
)freetypelib
, &vlen
);
2442 if( ( ERROR_SUCCESS
== r
) && ( type
== REG_SZ
) )
2444 ftname
= freetypelib
;
2446 RegCloseKey( hkey
);
2449 /* update locale dependent font info in registry */
2452 TRACE("Using freetype library %s\n",ftname
);
2453 ft_handle
= wine_dlopen(ftname
, RTLD_NOW
, NULL
, 0);
2455 TRACE("Can't find freetype library %s, trying %s instead\n", ftname
, SONAME_LIBFREETYPE
);
2456 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2459 "Wine cannot find the FreeType font library. To enable Wine to\n"
2460 "use TrueType fonts please install a version of FreeType greater than\n"
2461 "or equal to 2.0.5.\n"
2462 "http://www.freetype.org\n");
2467 #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;}
2469 LOAD_FUNCPTR(FT_Vector_Unit
)
2470 LOAD_FUNCPTR(FT_Done_Face
)
2471 LOAD_FUNCPTR(FT_Get_Char_Index
)
2472 LOAD_FUNCPTR(FT_Get_Module
)
2473 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2474 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2475 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2476 LOAD_FUNCPTR(FT_Init_FreeType
)
2477 LOAD_FUNCPTR(FT_Load_Glyph
)
2478 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2479 LOAD_FUNCPTR(FT_MulFix
)
2480 LOAD_FUNCPTR(FT_New_Face
)
2481 LOAD_FUNCPTR(FT_New_Memory_Face
)
2482 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2483 LOAD_FUNCPTR(FT_Outline_Transform
)
2484 LOAD_FUNCPTR(FT_Outline_Translate
)
2485 LOAD_FUNCPTR(FT_Select_Charmap
)
2486 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2487 LOAD_FUNCPTR(FT_Vector_Transform
)
2490 /* Don't warn if this one is missing */
2491 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2492 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2493 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2494 pFT_Get_Next_Char
= wine_dlsym(ft_handle
,"FT_Get_Next_Char", NULL
, 0);
2495 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2496 #ifdef HAVE_FREETYPE_FTWINFNT_H
2497 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2499 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2500 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2501 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2502 <= 2.0.3 has FT_Sqrt64 */
2506 if(pFT_Init_FreeType(&library
) != 0) {
2507 ERR("Can't init FreeType library\n");
2508 wine_dlclose(ft_handle
, NULL
, 0);
2512 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
2513 if (pFT_Library_Version
)
2515 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2517 if (FT_Version
.major
<=0)
2523 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2524 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2525 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2526 ((FT_Version
.patch
) & 0x0000ff);
2528 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2529 ERR("Failed to create font mutex\n");
2532 WaitForSingleObject(font_mutex
, INFINITE
);
2534 create_font_cache_key(&hkey_font_cache
, &disposition
);
2536 if(disposition
== REG_CREATED_NEW_KEY
)
2538 delete_external_font_keys();
2542 load_font_list_from_cache(hkey_font_cache
);
2544 RegCloseKey(hkey_font_cache
);
2546 reorder_font_list();
2552 if(!GetEnvironmentVariableW(cx_hack_var
, env_buf
, sizeof(env_buf
)/sizeof(WCHAR
)))
2555 if(disposition
== REG_CREATED_NEW_KEY
)
2556 update_reg_entries();
2558 init_system_links();
2560 ReleaseMutex(font_mutex
);
2564 "Wine cannot find certain functions that it needs inside the FreeType\n"
2565 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2566 "FreeType to at least version 2.0.5.\n"
2567 "http://www.freetype.org\n");
2568 wine_dlclose(ft_handle
, NULL
, 0);
2574 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2577 TT_HoriHeader
*pHori
;
2581 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2582 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2584 if(height
== 0) height
= 16;
2586 /* Calc. height of EM square:
2588 * For +ve lfHeight we have
2589 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2590 * Re-arranging gives:
2591 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2593 * For -ve lfHeight we have
2595 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2596 * with il = winAscent + winDescent - units_per_em]
2601 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2602 ppem
= ft_face
->units_per_EM
* height
/
2603 (pHori
->Ascender
- pHori
->Descender
);
2605 ppem
= ft_face
->units_per_EM
* height
/
2606 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2614 static struct font_mapping
*map_font( const char *name
)
2616 struct font_mapping
*mapping
;
2620 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2621 if (fstat( fd
, &st
) == -1) goto error
;
2623 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2625 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2627 mapping
->refcount
++;
2632 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2635 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2638 if (mapping
->data
== MAP_FAILED
)
2640 HeapFree( GetProcessHeap(), 0, mapping
);
2643 mapping
->refcount
= 1;
2644 mapping
->dev
= st
.st_dev
;
2645 mapping
->ino
= st
.st_ino
;
2646 mapping
->size
= st
.st_size
;
2647 list_add_tail( &mappings_list
, &mapping
->entry
);
2655 static void unmap_font( struct font_mapping
*mapping
)
2657 if (!--mapping
->refcount
)
2659 list_remove( &mapping
->entry
);
2660 munmap( mapping
->data
, mapping
->size
);
2661 HeapFree( GetProcessHeap(), 0, mapping
);
2665 static LONG
load_VDMX(GdiFont
*, LONG
);
2667 static FT_Face
OpenFontFile(GdiFont
*font
, char *file
, FT_Long face_index
, LONG width
, LONG height
)
2672 TRACE("%s, %ld, %d x %d\n", debugstr_a(file
), face_index
, width
, height
);
2674 if (!(font
->mapping
= map_font( file
)))
2676 WARN("failed to map %s\n", debugstr_a(file
));
2680 err
= pFT_New_Memory_Face(library
, font
->mapping
->data
, font
->mapping
->size
, face_index
, &ft_face
);
2682 ERR("FT_New_Face rets %d\n", err
);
2686 /* set it here, as load_VDMX needs it */
2687 font
->ft_face
= ft_face
;
2689 if(FT_IS_SCALABLE(ft_face
)) {
2690 /* load the VDMX table if we have one */
2691 font
->ppem
= load_VDMX(font
, height
);
2693 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2695 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2696 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2698 font
->ppem
= height
;
2699 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2700 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2706 static int get_nearest_charset(Face
*face
, int *cp
)
2708 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2709 a single face with the requested charset. The idea is to check if
2710 the selected font supports the current ANSI codepage, if it does
2711 return the corresponding charset, else return the first charset */
2714 int acp
= GetACP(), i
;
2718 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2719 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2720 return csi
.ciCharset
;
2722 for(i
= 0; i
< 32; i
++) {
2724 if(face
->fs
.fsCsb
[0] & fs0
) {
2725 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2727 return csi
.ciCharset
;
2730 FIXME("TCI failing on %x\n", fs0
);
2734 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2735 face
->fs
.fsCsb
[0], face
->file
);
2737 return DEFAULT_CHARSET
;
2740 static GdiFont
*alloc_font(void)
2742 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2743 ret
->gmsize
= INIT_GM_SIZE
;
2744 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
2745 ret
->gmsize
* sizeof(*ret
->gm
));
2747 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2748 ret
->total_kern_pairs
= (DWORD
)-1;
2749 ret
->kern_pairs
= NULL
;
2750 list_init(&ret
->hfontlist
);
2751 list_init(&ret
->child_fonts
);
2755 static void free_font(GdiFont
*font
)
2757 struct list
*cursor
, *cursor2
;
2759 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2761 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2762 struct list
*first_hfont
;
2763 HFONTLIST
*hfontlist
;
2764 list_remove(cursor
);
2767 first_hfont
= list_head(&child
->font
->hfontlist
);
2768 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2769 DeleteObject(hfontlist
->hfont
);
2770 HeapFree(GetProcessHeap(), 0, hfontlist
);
2771 free_font(child
->font
);
2773 HeapFree(GetProcessHeap(), 0, child
->file_name
);
2774 HeapFree(GetProcessHeap(), 0, child
);
2777 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2778 if (font
->mapping
) unmap_font( font
->mapping
);
2779 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2780 HeapFree(GetProcessHeap(), 0, font
->potm
);
2781 HeapFree(GetProcessHeap(), 0, font
->name
);
2782 HeapFree(GetProcessHeap(), 0, font
->gm
);
2783 HeapFree(GetProcessHeap(), 0, font
);
2787 /*************************************************************
2790 * load the vdmx entry for the specified height
2793 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2794 ( ( (FT_ULong)_x4 << 24 ) | \
2795 ( (FT_ULong)_x3 << 16 ) | \
2796 ( (FT_ULong)_x2 << 8 ) | \
2799 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2814 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2818 BYTE devXRatio
, devYRatio
;
2819 USHORT numRecs
, numRatios
;
2820 DWORD result
, offset
= -1;
2824 /* For documentation on VDMX records, see
2825 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2828 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2830 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2833 /* FIXME: need the real device aspect ratio */
2837 numRecs
= GET_BE_WORD(hdr
[1]);
2838 numRatios
= GET_BE_WORD(hdr
[2]);
2840 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2841 for(i
= 0; i
< numRatios
; i
++) {
2844 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2845 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2848 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2850 if((ratio
.xRatio
== 0 &&
2851 ratio
.yStartRatio
== 0 &&
2852 ratio
.yEndRatio
== 0) ||
2853 (devXRatio
== ratio
.xRatio
&&
2854 devYRatio
>= ratio
.yStartRatio
&&
2855 devYRatio
<= ratio
.yEndRatio
))
2857 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2858 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2859 offset
= GET_BE_WORD(tmp
);
2865 FIXME("No suitable ratio found\n");
2869 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2871 BYTE startsz
, endsz
;
2874 recs
= GET_BE_WORD(group
.recs
);
2875 startsz
= group
.startsz
;
2876 endsz
= group
.endsz
;
2878 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2880 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2881 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2882 if(result
== GDI_ERROR
) {
2883 FIXME("Failed to retrieve vTable\n");
2888 for(i
= 0; i
< recs
; i
++) {
2889 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2890 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2891 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2893 if(yMax
+ -yMin
== height
) {
2896 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2899 if(yMax
+ -yMin
> height
) {
2902 goto end
; /* failed */
2904 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2905 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2906 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2907 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2913 TRACE("ppem not found for height %d\n", height
);
2917 if(ppem
< startsz
|| ppem
> endsz
)
2920 for(i
= 0; i
< recs
; i
++) {
2922 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2924 if(yPelHeight
> ppem
)
2927 if(yPelHeight
== ppem
) {
2928 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2929 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2930 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2936 HeapFree(GetProcessHeap(), 0, vTable
);
2942 static BOOL
fontcmp(GdiFont
*font
, FONT_DESC
*fd
)
2944 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2945 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2946 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2947 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2948 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2951 static void calc_hash(FONT_DESC
*pfd
)
2953 DWORD hash
= 0, *ptr
, two_chars
;
2957 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2959 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2961 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2963 pwc
= (WCHAR
*)&two_chars
;
2965 *pwc
= toupperW(*pwc
);
2967 *pwc
= toupperW(*pwc
);
2971 hash
^= !pfd
->can_use_bitmap
;
2976 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2981 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2983 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
2984 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2985 fd
.can_use_bitmap
= can_use_bitmap
;
2988 /* try the in-use list */
2989 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2990 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2991 if(!fontcmp(ret
, &fd
)) {
2992 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2993 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2994 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2995 if(hflist
->hfont
== hfont
)
2998 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2999 hflist
->hfont
= hfont
;
3000 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3005 /* then the unused list */
3006 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3007 while(font_elem_ptr
) {
3008 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3009 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3010 if(!fontcmp(ret
, &fd
)) {
3011 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3012 assert(list_empty(&ret
->hfontlist
));
3013 TRACE("Found %p in unused list\n", ret
);
3014 list_remove(&ret
->entry
);
3015 list_add_head(&gdi_font_list
, &ret
->entry
);
3016 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3017 hflist
->hfont
= hfont
;
3018 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3026 /*************************************************************
3027 * create_child_font_list
3029 static BOOL
create_child_font_list(GdiFont
*font
)
3032 SYSTEM_LINKS
*font_link
;
3033 CHILD_FONT
*font_link_entry
, *new_child
;
3035 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3037 if(!strcmpW(font_link
->font_name
, font
->name
))
3039 TRACE("found entry in system list\n");
3040 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3042 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3043 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
3044 new_child
->index
= font_link_entry
->index
;
3045 new_child
->font
= NULL
;
3046 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3047 TRACE("font %s %d\n", debugstr_a(new_child
->file_name
), new_child
->index
);
3057 /*************************************************************
3058 * WineEngCreateFontInstance
3061 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3064 Face
*face
, *best
, *best_bitmap
;
3065 Family
*family
, *last_resort_family
;
3066 struct list
*family_elem_ptr
, *face_elem_ptr
;
3067 INT height
, width
= 0;
3068 unsigned int score
= 0, new_score
;
3069 signed int diff
= 0, newdiff
;
3070 BOOL bd
, it
, can_use_bitmap
;
3075 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
3077 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
3078 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3079 if(hflist
->hfont
== hfont
)
3083 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3084 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3086 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3087 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3088 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3091 /* check the cache first */
3092 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
3093 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3097 TRACE("not in cache\n");
3098 if(list_empty(&font_list
)) /* No fonts installed */
3100 TRACE("No fonts installed\n");
3103 if(!have_installed_roman_font
)
3105 TRACE("No roman font installed\n");
3111 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3112 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
3113 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3114 calc_hash(&ret
->font_desc
);
3115 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3116 hflist
->hfont
= hfont
;
3117 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3120 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3121 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3122 original value lfCharSet. Note this is a special case for
3123 Symbol and doesn't happen at least for "Wingdings*" */
3125 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3126 lf
.lfCharSet
= SYMBOL_CHARSET
;
3128 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3129 switch(lf
.lfCharSet
) {
3130 case DEFAULT_CHARSET
:
3131 csi
.fs
.fsCsb
[0] = 0;
3134 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3135 csi
.fs
.fsCsb
[0] = 0;
3141 if(lf
.lfFaceName
[0] != '\0') {
3143 SYSTEM_LINKS
*font_link
;
3144 CHILD_FONT
*font_link_entry
;
3146 psub
= get_font_subst(&font_subst_list
, lf
.lfFaceName
, lf
.lfCharSet
);
3149 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
3150 debugstr_w(psub
->to
.name
));
3151 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3154 /* We want a match on name and charset or just name if
3155 charset was DEFAULT_CHARSET. If the latter then
3156 we fixup the returned charset later in get_nearest_charset
3157 where we'll either use the charset of the current ansi codepage
3158 or if that's unavailable the first charset that the font supports.
3160 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3161 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3162 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3163 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3164 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3165 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3166 if(face
->scalable
|| can_use_bitmap
)
3173 * Try check the SystemLink list first for a replacement font.
3174 * We may find good replacements there.
3176 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3178 if(!strcmpiW(font_link
->font_name
, lf
.lfFaceName
))
3180 TRACE("found entry in system list\n");
3181 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3183 face
= find_face_from_path_index(font_link_entry
->file_name
,
3184 font_link_entry
->index
);
3187 family
= face
->family
;
3188 if(csi
.fs
.fsCsb
[0] &
3189 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3191 if(face
->scalable
|| can_use_bitmap
)
3200 /* If requested charset was DEFAULT_CHARSET then try using charset
3201 corresponding to the current ansi codepage */
3202 if(!csi
.fs
.fsCsb
[0]) {
3204 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3205 FIXME("TCI failed on codepage %d\n", acp
);
3206 csi
.fs
.fsCsb
[0] = 0;
3208 lf
.lfCharSet
= csi
.ciCharset
;
3211 /* Face families are in the top 4 bits of lfPitchAndFamily,
3212 so mask with 0xF0 before testing */
3214 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3215 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3216 strcpyW(lf
.lfFaceName
, defFixed
);
3217 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3218 strcpyW(lf
.lfFaceName
, defSerif
);
3219 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3220 strcpyW(lf
.lfFaceName
, defSans
);
3222 strcpyW(lf
.lfFaceName
, defSans
);
3223 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3224 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3225 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3226 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3227 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3228 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3229 if(face
->scalable
|| can_use_bitmap
)
3235 last_resort_family
= NULL
;
3236 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3237 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3238 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3239 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3240 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3243 if(can_use_bitmap
&& !last_resort_family
)
3244 last_resort_family
= family
;
3249 if(last_resort_family
) {
3250 family
= last_resort_family
;
3251 csi
.fs
.fsCsb
[0] = 0;
3255 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3256 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3257 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3258 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3259 if(face
->scalable
) {
3260 csi
.fs
.fsCsb
[0] = 0;
3261 WARN("just using first face for now\n");
3264 if(can_use_bitmap
&& !last_resort_family
)
3265 last_resort_family
= family
;
3268 if(!last_resort_family
) {
3269 FIXME("can't find a single appropriate font - bailing\n");
3274 WARN("could only find a bitmap font - this will probably look awful!\n");
3275 family
= last_resort_family
;
3276 csi
.fs
.fsCsb
[0] = 0;
3279 it
= lf
.lfItalic
? 1 : 0;
3280 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3282 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
3283 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
3285 face
= best
= best_bitmap
= NULL
;
3286 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3288 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3290 new_score
= (face
->Italic
^ it
) + (face
->Bold
^ bd
);
3291 if(!best
|| new_score
<= score
)
3293 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3294 face
->Italic
, face
->Bold
, it
, bd
);
3297 if(best
->scalable
&& score
== 0) break;
3301 newdiff
= height
- (signed int)(best
->size
.height
);
3303 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3304 if(!best_bitmap
|| new_score
< score
||
3305 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3307 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3310 if(score
== 0 && diff
== 0) break;
3317 face
= best
->scalable
? best
: best_bitmap
;
3318 ret
->fake_italic
= (it
&& !face
->Italic
);
3319 ret
->fake_bold
= (bd
&& !face
->Bold
);
3321 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
3323 if(csi
.fs
.fsCsb
[0]) {
3324 ret
->charset
= lf
.lfCharSet
;
3325 ret
->codepage
= csi
.ciACP
;
3328 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3330 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family
->FamilyName
),
3331 debugstr_w(face
->StyleName
), face
->file
, face
->face_index
);
3333 if(!face
->scalable
) {
3334 width
= face
->size
.x_ppem
>> 6;
3335 height
= face
->size
.y_ppem
>> 6;
3337 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
, width
, height
);
3345 if (ret
->charset
== SYMBOL_CHARSET
&&
3346 !pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3349 else if (!pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3353 pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3356 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3357 ret
->name
= strdupW(family
->FamilyName
);
3358 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3359 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3360 create_child_font_list(ret
);
3362 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3364 ret
->aveWidth
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfWidth
: 0;
3365 list_add_head(&gdi_font_list
, &ret
->entry
);
3369 static void dump_gdi_font_list(void)
3372 struct list
*elem_ptr
;
3374 TRACE("---------- gdiFont Cache ----------\n");
3375 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3376 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3377 TRACE("gdiFont=%p %s %d\n",
3378 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3381 TRACE("---------- Unused gdiFont Cache ----------\n");
3382 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3383 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3384 TRACE("gdiFont=%p %s %d\n",
3385 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3389 /*************************************************************
3390 * WineEngDestroyFontInstance
3392 * free the gdiFont associated with this handle
3395 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3400 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3403 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3405 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3406 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3407 if(hflist
->hfont
== handle
)
3409 TRACE("removing child font %p from child list\n", gdiFont
);
3410 list_remove(&gdiFont
->entry
);
3415 TRACE("destroying hfont=%p\n", handle
);
3417 dump_gdi_font_list();
3419 font_elem_ptr
= list_head(&gdi_font_list
);
3420 while(font_elem_ptr
) {
3421 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3422 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3424 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3425 while(hfontlist_elem_ptr
) {
3426 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3427 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3428 if(hflist
->hfont
== handle
) {
3429 list_remove(&hflist
->entry
);
3430 HeapFree(GetProcessHeap(), 0, hflist
);
3434 if(list_empty(&gdiFont
->hfontlist
)) {
3435 TRACE("Moving to Unused list\n");
3436 list_remove(&gdiFont
->entry
);
3437 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3442 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3443 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3444 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3445 while(font_elem_ptr
) {
3446 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3447 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3448 TRACE("freeing %p\n", gdiFont
);
3449 list_remove(&gdiFont
->entry
);
3455 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3456 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3458 OUTLINETEXTMETRICW
*potm
= NULL
;
3460 TEXTMETRICW tm
, *ptm
;
3461 GdiFont
*font
= alloc_font();
3464 if (face
->cache_valid
)
3467 memcpy(pelf
,&face
->elf
,sizeof(ENUMLOGFONTEXW
));
3468 memcpy(pntm
,&face
->ntm
,sizeof(NEWTEXTMETRICEXW
));
3469 *ptype
= face
->type
;
3473 if(face
->scalable
) {
3477 height
= face
->size
.y_ppem
>> 6;
3478 width
= face
->size
.x_ppem
>> 6;
3481 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, width
, height
)))
3487 font
->name
= strdupW(face
->family
->FamilyName
);
3489 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
3491 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
3493 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3494 WineEngGetOutlineTextMetrics(font
, size
, potm
);
3495 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
3497 WineEngGetTextMetrics(font
, &tm
);
3501 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
3502 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
3503 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
3504 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
3505 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
3506 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
3507 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
3508 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
3509 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
3510 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
3511 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
3512 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
3513 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
3514 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
3515 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
3516 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
3517 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
3518 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
3519 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
3520 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
3521 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
3522 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3523 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3524 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3526 *ptype
= ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
3527 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
3528 *ptype
|= RASTER_FONTTYPE
;
3530 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
3531 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
3532 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
3534 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3535 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3536 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
3539 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
3541 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3542 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
3544 lstrcpynW(pelf
->elfFullName
,
3545 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
3547 lstrcpynW(pelf
->elfStyle
,
3548 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
3551 HeapFree(GetProcessHeap(), 0, potm
);
3553 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3555 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3556 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
3557 pelf
->elfStyle
[0] = '\0';
3560 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3562 memcpy(&face
->elf
,pelf
,sizeof(ENUMLOGFONTEXW
));
3563 memcpy(&face
->ntm
,pntm
,sizeof(NEWTEXTMETRICEXW
));
3564 face
->type
= *ptype
;
3565 face
->cache_valid
= TRUE
;
3570 /*************************************************************
3574 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3578 struct list
*family_elem_ptr
, *face_elem_ptr
;
3580 NEWTEXTMETRICEXW ntm
;
3581 DWORD type
, ret
= 1;
3587 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3589 if(plf
->lfFaceName
[0]) {
3591 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3594 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3595 debugstr_w(psub
->to
.name
));
3596 memcpy(&lf
, plf
, sizeof(lf
));
3597 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3601 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3602 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3603 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3604 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3605 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3606 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3607 for(i
= 0; i
< 32; i
++) {
3608 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3609 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3610 strcpyW(elf
.elfScript
, OEM_DOSW
);
3611 i
= 32; /* break out of loop */
3612 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3615 fs
.fsCsb
[0] = 1L << i
;
3617 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3619 csi
.ciCharset
= DEFAULT_CHARSET
;
3620 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3621 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3622 elf
.elfLogFont
.lfCharSet
=
3623 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3625 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3627 FIXME("Unknown elfscript for bit %d\n", i
);
3630 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3631 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3632 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3633 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3634 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3635 ntm
.ntmTm
.ntmFlags
);
3636 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3643 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3644 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3645 face_elem_ptr
= list_head(&family
->faces
);
3646 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3647 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3648 for(i
= 0; i
< 32; i
++) {
3649 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3650 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3651 strcpyW(elf
.elfScript
, OEM_DOSW
);
3652 i
= 32; /* break out of loop */
3653 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3656 fs
.fsCsb
[0] = 1L << i
;
3658 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3660 csi
.ciCharset
= DEFAULT_CHARSET
;
3661 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3662 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3663 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3666 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3668 FIXME("Unknown elfscript for bit %d\n", i
);
3671 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3672 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3673 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3674 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3675 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3676 ntm
.ntmTm
.ntmFlags
);
3677 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3686 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3688 pt
->x
.value
= vec
->x
>> 6;
3689 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3690 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3691 pt
->y
.value
= vec
->y
>> 6;
3692 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3693 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3697 /***************************************************
3698 * According to the MSDN documentation on WideCharToMultiByte,
3699 * certain codepages cannot set the default_used parameter.
3700 * This returns TRUE if the codepage can set that parameter, false else
3701 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3703 static BOOL
codepage_sets_default_used(UINT codepage
)
3716 static FT_UInt
get_glyph_index(GdiFont
*font
, UINT glyph
)
3718 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
3719 WCHAR wc
= (WCHAR
)glyph
;
3721 BOOL
*default_used_pointer
;
3724 default_used_pointer
= NULL
;
3725 default_used
= FALSE
;
3726 if (codepage_sets_default_used(font
->codepage
))
3727 default_used_pointer
= &default_used
;
3728 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
3731 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
3732 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
3736 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
3737 glyph
= glyph
+ 0xf000;
3738 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
3741 /*************************************************************
3742 * WineEngGetGlyphIndices
3744 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3746 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
3747 LPWORD pgi
, DWORD flags
)
3750 WCHAR default_char
= 0;
3753 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0x001f; /* Indicate non existence */
3755 for(i
= 0; i
< count
; i
++)
3757 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
3762 WineEngGetTextMetrics(font
, &textm
);
3763 default_char
= textm
.tmDefaultChar
;
3765 pgi
[i
] = default_char
;
3771 /*************************************************************
3772 * WineEngGetGlyphOutline
3774 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3775 * except that the first parameter is the HWINEENGFONT of the font in
3776 * question rather than an HDC.
3779 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
3780 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3783 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
3784 FT_Face ft_face
= font
->ft_face
;
3785 FT_UInt glyph_index
;
3786 DWORD width
, height
, pitch
, needed
= 0;
3787 FT_Bitmap ft_bitmap
;
3789 INT left
, right
, top
= 0, bottom
= 0;
3791 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
|
3792 FT_LOAD_NO_AUTOHINT
;
3793 float widthRatio
= 1.0;
3794 FT_Matrix transMat
= identityMat
;
3795 BOOL needsTransform
= FALSE
;
3798 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
3799 buflen
, buf
, lpmat
);
3801 if(format
& GGO_GLYPH_INDEX
) {
3802 glyph_index
= glyph
;
3803 format
&= ~GGO_GLYPH_INDEX
;
3805 glyph_index
= get_glyph_index(font
, glyph
);
3807 if(glyph_index
>= font
->gmsize
) {
3808 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
3809 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
3810 font
->gmsize
* sizeof(*font
->gm
));
3812 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
3813 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
3814 return 1; /* FIXME */
3818 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
3819 load_flags
|= FT_LOAD_NO_BITMAP
;
3821 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
3824 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
3828 /* Scaling factor */
3829 if (font
->aveWidth
&& font
->potm
) {
3830 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
3833 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
3834 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
3836 font
->gm
[glyph_index
].adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
3837 font
->gm
[glyph_index
].lsb
= left
>> 6;
3838 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
3840 /* Scaling transform */
3841 if(font
->aveWidth
) {
3843 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
3846 scaleMat
.yy
= (1 << 16);
3848 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
3849 needsTransform
= TRUE
;
3852 /* Slant transform */
3853 if (font
->fake_italic
) {
3856 slantMat
.xx
= (1 << 16);
3857 slantMat
.xy
= ((1 << 16) >> 2);
3859 slantMat
.yy
= (1 << 16);
3860 pFT_Matrix_Multiply(&slantMat
, &transMat
);
3861 needsTransform
= TRUE
;
3864 /* Rotation transform */
3865 if(font
->orientation
) {
3866 FT_Matrix rotationMat
;
3868 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
3869 pFT_Vector_Unit(&vecAngle
, angle
);
3870 rotationMat
.xx
= vecAngle
.x
;
3871 rotationMat
.xy
= -vecAngle
.y
;
3872 rotationMat
.yx
= -rotationMat
.xy
;
3873 rotationMat
.yy
= rotationMat
.xx
;
3875 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
3876 needsTransform
= TRUE
;
3879 /* Extra transformation specified by caller */
3882 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
3883 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
3884 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
3885 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
3886 pFT_Matrix_Multiply(&extraMat
, &transMat
);
3887 needsTransform
= TRUE
;
3890 if(!needsTransform
) {
3891 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
3892 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
3893 ft_face
->glyph
->metrics
.height
) & -64;
3894 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
3895 lpgm
->gmCellIncY
= 0;
3899 for(xc
= 0; xc
< 2; xc
++) {
3900 for(yc
= 0; yc
< 2; yc
++) {
3901 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
3902 xc
* ft_face
->glyph
->metrics
.width
);
3903 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
3904 yc
* ft_face
->glyph
->metrics
.height
;
3905 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
3906 pFT_Vector_Transform(&vec
, &transMat
);
3907 if(xc
== 0 && yc
== 0) {
3908 left
= right
= vec
.x
;
3909 top
= bottom
= vec
.y
;
3911 if(vec
.x
< left
) left
= vec
.x
;
3912 else if(vec
.x
> right
) right
= vec
.x
;
3913 if(vec
.y
< bottom
) bottom
= vec
.y
;
3914 else if(vec
.y
> top
) top
= vec
.y
;
3919 right
= (right
+ 63) & -64;
3920 bottom
= bottom
& -64;
3921 top
= (top
+ 63) & -64;
3923 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
3924 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
3926 pFT_Vector_Transform(&vec
, &transMat
);
3927 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
3928 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
3930 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
3931 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
3932 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
3933 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
3935 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
3936 font
->gm
[glyph_index
].init
= TRUE
;
3938 if(format
== GGO_METRICS
)
3939 return 1; /* FIXME */
3941 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
3942 TRACE("loaded a bitmap\n");
3948 width
= lpgm
->gmBlackBoxX
;
3949 height
= lpgm
->gmBlackBoxY
;
3950 pitch
= ((width
+ 31) >> 5) << 2;
3951 needed
= pitch
* height
;
3953 if(!buf
|| !buflen
) break;
3955 switch(ft_face
->glyph
->format
) {
3956 case ft_glyph_format_bitmap
:
3958 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3959 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
3960 INT h
= ft_face
->glyph
->bitmap
.rows
;
3962 memcpy(dst
, src
, w
);
3963 src
+= ft_face
->glyph
->bitmap
.pitch
;
3969 case ft_glyph_format_outline
:
3970 ft_bitmap
.width
= width
;
3971 ft_bitmap
.rows
= height
;
3972 ft_bitmap
.pitch
= pitch
;
3973 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
3974 ft_bitmap
.buffer
= buf
;
3976 if(needsTransform
) {
3977 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3980 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3982 /* Note: FreeType will only set 'black' bits for us. */
3983 memset(buf
, 0, needed
);
3984 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3988 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3993 case GGO_GRAY2_BITMAP
:
3994 case GGO_GRAY4_BITMAP
:
3995 case GGO_GRAY8_BITMAP
:
3996 case WINE_GGO_GRAY16_BITMAP
:
3998 unsigned int mult
, row
, col
;
4001 /****************** CodeWeavers hack to fix HL2 crash **************************
4003 * Both glyphs 0x2e and 0x39 of this font get rendered to a larger
4004 * size with FreeType than under Windows, and HL2 uses a fixed size
4005 * buffer on the stack to copy the data into. For now we'll clip glyphs
4006 * from that font into a rather smaller BBox
4008 ******************************************************************************/
4009 if(!strcmp(ft_face
->family_name
, "HL2MP") ||
4010 !strcmp(ft_face
->family_name
, "csd"))
4013 if(lpgm
->gmBlackBoxX
)
4014 lpgm
->gmBlackBoxX
--;
4016 for(i
= 0; i
< 2; i
++)
4018 if(lpgm
->gmBlackBoxY
)
4020 lpgm
->gmBlackBoxY
--;
4021 lpgm
->gmptGlyphOrigin
.y
--;
4025 /*********************************** End CW's hack ****************************/
4027 width
= lpgm
->gmBlackBoxX
;
4028 height
= lpgm
->gmBlackBoxY
;
4029 pitch
= (width
+ 3) / 4 * 4;
4030 needed
= pitch
* height
;
4032 if(!buf
|| !buflen
) break;
4033 ft_bitmap
.width
= width
;
4034 ft_bitmap
.rows
= height
;
4035 ft_bitmap
.pitch
= pitch
;
4036 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4037 ft_bitmap
.buffer
= buf
;
4039 if(needsTransform
) {
4040 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4043 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4045 memset(ft_bitmap
.buffer
, 0, buflen
);
4047 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4049 if(format
== GGO_GRAY2_BITMAP
)
4051 else if(format
== GGO_GRAY4_BITMAP
)
4053 else if(format
== GGO_GRAY8_BITMAP
)
4055 else if(format
== WINE_GGO_GRAY16_BITMAP
)
4063 for(row
= 0; row
< height
; row
++) {
4065 for(col
= 0; col
< width
; col
++, ptr
++) {
4066 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4075 int contour
, point
= 0, first_pt
;
4076 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4077 TTPOLYGONHEADER
*pph
;
4079 DWORD pph_start
, cpfx
, type
;
4081 if(buflen
== 0) buf
= NULL
;
4083 if (needsTransform
&& buf
) {
4084 pFT_Outline_Transform(outline
, &transMat
);
4087 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4089 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4092 pph
->dwType
= TT_POLYGON_TYPE
;
4093 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4095 needed
+= sizeof(*pph
);
4097 while(point
<= outline
->contours
[contour
]) {
4098 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4099 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4100 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
4104 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4107 } while(point
<= outline
->contours
[contour
] &&
4108 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4109 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4110 /* At the end of a contour Windows adds the start point, but
4112 if(point
> outline
->contours
[contour
] &&
4113 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4115 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
4117 } else if(point
<= outline
->contours
[contour
] &&
4118 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4119 /* add closing pt for bezier */
4121 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4129 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4132 pph
->cb
= needed
- pph_start
;
4138 /* Convert the quadratic Beziers to cubic Beziers.
4139 The parametric eqn for a cubic Bezier is, from PLRM:
4140 r(t) = at^3 + bt^2 + ct + r0
4141 with the control points:
4146 A quadratic Beizer has the form:
4147 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4149 So equating powers of t leads to:
4150 r1 = 2/3 p1 + 1/3 p0
4151 r2 = 2/3 p1 + 1/3 p2
4152 and of course r0 = p0, r3 = p2
4155 int contour
, point
= 0, first_pt
;
4156 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4157 TTPOLYGONHEADER
*pph
;
4159 DWORD pph_start
, cpfx
, type
;
4160 FT_Vector cubic_control
[4];
4161 if(buflen
== 0) buf
= NULL
;
4163 if (needsTransform
&& buf
) {
4164 pFT_Outline_Transform(outline
, &transMat
);
4167 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4169 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4172 pph
->dwType
= TT_POLYGON_TYPE
;
4173 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4175 needed
+= sizeof(*pph
);
4177 while(point
<= outline
->contours
[contour
]) {
4178 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4179 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4180 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
4183 if(type
== TT_PRIM_LINE
) {
4185 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4189 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4192 /* FIXME: Possible optimization in endpoint calculation
4193 if there are two consecutive curves */
4194 cubic_control
[0] = outline
->points
[point
-1];
4195 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4196 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
4197 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
4198 cubic_control
[0].x
>>= 1;
4199 cubic_control
[0].y
>>= 1;
4201 if(point
+1 > outline
->contours
[contour
])
4202 cubic_control
[3] = outline
->points
[first_pt
];
4204 cubic_control
[3] = outline
->points
[point
+1];
4205 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
4206 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
4207 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
4208 cubic_control
[3].x
>>= 1;
4209 cubic_control
[3].y
>>= 1;
4212 /* r1 = 1/3 p0 + 2/3 p1
4213 r2 = 1/3 p2 + 2/3 p1 */
4214 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
4215 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
4216 cubic_control
[2] = cubic_control
[1];
4217 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
4218 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
4219 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
4220 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
4222 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
4223 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
4224 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
4229 } while(point
<= outline
->contours
[contour
] &&
4230 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4231 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4232 /* At the end of a contour Windows adds the start point,
4233 but only for Beziers and we've already done that.
4235 if(point
<= outline
->contours
[contour
] &&
4236 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4237 /* This is the closing pt of a bezier, but we've already
4238 added it, so just inc point and carry on */
4245 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4248 pph
->cb
= needed
- pph_start
;
4254 FIXME("Unsupported format %d\n", format
);
4260 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
4262 FT_Face ft_face
= font
->ft_face
;
4263 #ifdef HAVE_FREETYPE_FTWINFNT_H
4264 FT_WinFNT_HeaderRec winfnt_header
;
4266 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
4267 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
4268 font
->potm
->otmSize
= size
;
4270 #define TM font->potm->otmTextMetrics
4271 #ifdef HAVE_FREETYPE_FTWINFNT_H
4272 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
4274 TM
.tmHeight
= winfnt_header
.pixel_height
;
4275 TM
.tmAscent
= winfnt_header
.ascent
;
4276 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
4277 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
4278 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
4279 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
4280 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4281 TM
.tmWeight
= winfnt_header
.weight
;
4283 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4284 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4285 TM
.tmFirstChar
= winfnt_header
.first_char
;
4286 TM
.tmLastChar
= winfnt_header
.last_char
;
4287 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4288 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4289 TM
.tmItalic
= winfnt_header
.italic
;
4290 TM
.tmUnderlined
= font
->underline
;
4291 TM
.tmStruckOut
= font
->strikeout
;
4292 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4293 TM
.tmCharSet
= winfnt_header
.charset
;
4298 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4299 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4300 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4301 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4302 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4303 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4304 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4305 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4307 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4308 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4310 TM
.tmLastChar
= 255;
4311 TM
.tmDefaultChar
= 32;
4312 TM
.tmBreakChar
= 32;
4313 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4314 TM
.tmUnderlined
= font
->underline
;
4315 TM
.tmStruckOut
= font
->strikeout
;
4316 /* NB inverted meaning of TMPF_FIXED_PITCH */
4317 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4318 TM
.tmCharSet
= font
->charset
;
4325 /*************************************************************
4326 * WineEngGetTextMetrics
4329 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4332 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4333 if(!get_bitmap_text_metrics(font
))
4336 if(!font
->potm
) return FALSE
;
4337 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
4339 if (font
->aveWidth
) {
4340 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4346 /*************************************************************
4347 * WineEngGetOutlineTextMetrics
4350 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4351 OUTLINETEXTMETRICW
*potm
)
4353 FT_Face ft_face
= font
->ft_face
;
4354 UINT needed
, lenfam
, lensty
, ret
;
4356 TT_HoriHeader
*pHori
;
4357 TT_Postscript
*pPost
;
4358 FT_Fixed x_scale
, y_scale
;
4359 WCHAR
*family_nameW
, *style_nameW
;
4360 static const WCHAR spaceW
[] = {' ', '\0'};
4362 INT ascent
, descent
;
4364 TRACE("font=%p\n", font
);
4366 if(!FT_IS_SCALABLE(ft_face
))
4370 if(cbSize
>= font
->potm
->otmSize
)
4371 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4372 return font
->potm
->otmSize
;
4376 needed
= sizeof(*potm
);
4378 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
4379 family_nameW
= strdupW(font
->name
);
4381 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
4383 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
4384 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
4385 style_nameW
, lensty
/sizeof(WCHAR
));
4387 /* These names should be read from the TT name table */
4389 /* length of otmpFamilyName */
4392 /* length of otmpFaceName */
4393 if(!strcasecmp(ft_face
->style_name
, "regular")) {
4394 needed
+= lenfam
; /* just the family name */
4396 needed
+= lenfam
+ lensty
; /* family + " " + style */
4399 /* length of otmpStyleName */
4402 /* length of otmpFullName */
4403 needed
+= lenfam
+ lensty
;
4406 x_scale
= ft_face
->size
->metrics
.x_scale
;
4407 y_scale
= ft_face
->size
->metrics
.y_scale
;
4409 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4411 FIXME("Can't find OS/2 table - not TT font?\n");
4416 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4418 FIXME("Can't find HHEA table - not TT font?\n");
4423 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
4425 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",
4426 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
4427 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
4428 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
4429 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
4430 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
4432 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
4433 font
->potm
->otmSize
= needed
;
4435 #define TM font->potm->otmTextMetrics
4437 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
4438 ascent
= pHori
->Ascender
;
4439 descent
= -pHori
->Descender
;
4441 ascent
= pOS2
->usWinAscent
;
4442 descent
= pOS2
->usWinDescent
;
4446 TM
.tmAscent
= font
->yMax
;
4447 TM
.tmDescent
= -font
->yMin
;
4448 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4450 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4451 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4452 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4453 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4456 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4459 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4461 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4462 ((ascent
+ descent
) -
4463 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4465 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4466 if (TM
.tmAveCharWidth
== 0) {
4467 TM
.tmAveCharWidth
= 1;
4469 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4470 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4472 TM
.tmDigitizedAspectX
= 300;
4473 TM
.tmDigitizedAspectY
= 300;
4474 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4475 * symbol range to 0 - f0ff
4477 if (font
->charset
== SYMBOL_CHARSET
)
4480 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4481 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4482 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4483 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4484 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4485 TM
.tmUnderlined
= font
->underline
;
4486 TM
.tmStruckOut
= font
->strikeout
;
4488 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4489 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4490 (pOS2
->version
== 0xFFFFU
||
4491 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4492 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4494 TM
.tmPitchAndFamily
= 0;
4496 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4497 case PAN_FAMILY_SCRIPT
:
4498 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4500 case PAN_FAMILY_DECORATIVE
:
4501 case PAN_FAMILY_PICTORIAL
:
4502 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4504 case PAN_FAMILY_TEXT_DISPLAY
:
4505 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4506 TM
.tmPitchAndFamily
= FF_MODERN
;
4508 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4509 case PAN_SERIF_NORMAL_SANS
:
4510 case PAN_SERIF_OBTUSE_SANS
:
4511 case PAN_SERIF_PERP_SANS
:
4512 TM
.tmPitchAndFamily
|= FF_SWISS
;
4515 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4520 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4523 if(FT_IS_SCALABLE(ft_face
))
4524 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4525 if(FT_IS_SFNT(ft_face
))
4526 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4528 TM
.tmCharSet
= font
->charset
;
4531 font
->potm
->otmFiller
= 0;
4532 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4533 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4534 font
->potm
->otmfsType
= pOS2
->fsType
;
4535 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4536 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4537 font
->potm
->otmItalicAngle
= 0; /* POST table */
4538 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4539 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4540 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4541 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4542 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4543 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
4544 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4545 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
4546 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
4547 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
4548 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
4549 font
->potm
->otmMacDescent
= 0;
4550 font
->potm
->otmMacLineGap
= 0;
4551 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
4552 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
4553 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
4554 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
4555 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
4556 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
4557 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
4558 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
4559 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
4560 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
4561 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
4563 font
->potm
->otmsUnderscoreSize
= 0;
4564 font
->potm
->otmsUnderscorePosition
= 0;
4566 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
4567 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
4570 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4571 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
4572 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
4573 strcpyW((WCHAR
*)cp
, family_nameW
);
4575 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
4576 strcpyW((WCHAR
*)cp
, style_nameW
);
4578 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
4579 strcpyW((WCHAR
*)cp
, family_nameW
);
4580 if(strcasecmp(ft_face
->style_name
, "regular")) {
4581 strcatW((WCHAR
*)cp
, spaceW
);
4582 strcatW((WCHAR
*)cp
, style_nameW
);
4583 cp
+= lenfam
+ lensty
;
4586 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
4587 strcpyW((WCHAR
*)cp
, family_nameW
);
4588 strcatW((WCHAR
*)cp
, spaceW
);
4589 strcatW((WCHAR
*)cp
, style_nameW
);
4592 if(potm
&& needed
<= cbSize
)
4593 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4596 HeapFree(GetProcessHeap(), 0, style_nameW
);
4597 HeapFree(GetProcessHeap(), 0, family_nameW
);
4602 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
4604 HFONTLIST
*hfontlist
;
4606 static DWORD child_font_no
= 0;
4607 static const WCHAR fmt
[] = {'c','h','i','l','d','%','0','8','x',0};
4609 child
->font
= alloc_font();
4610 child
->font
->ft_face
= OpenFontFile(child
->font
, child
->file_name
, child
->index
, 0, -font
->ppem
);
4611 if(!child
->font
->ft_face
)
4613 free_font(child
->font
);
4618 child
->font
->orientation
= font
->orientation
;
4619 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
4620 memcpy(&lf
, &font
->font_desc
.lf
, sizeof(lf
));
4621 sprintfW(lf
.lfFaceName
, fmt
, child_font_no
++);
4622 hfontlist
->hfont
= CreateFontIndirectW(&lf
);
4623 child
->font
->name
= strdupW(lf
.lfFaceName
);
4624 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
4625 child
->font
->base_font
= font
;
4626 list_add_head(&child_font_list
, &child
->font
->entry
);
4627 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
4631 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
4634 CHILD_FONT
*child_font
;
4637 font
= font
->base_font
;
4639 *linked_font
= font
;
4641 if((*glyph
= get_glyph_index(font
, c
)))
4644 /* Codeweavers Hack.
4645 * Counterstrike: Source is being greedy with memory and allocates
4646 * about 70 versions of tahoma and then looks for glyphs in the whole
4647 * 0 to 127 range. This causes us to load our Japanese font links for
4648 * every dc, which causes us to use up all our memory.
4650 * This is a range, given to me by Huw that we can resonably expect that
4651 * an app would not be relying on system links to provide a glyph for.
4652 * This allows CS to load and not load all the system links and thus.
4653 * not use up all its memory for Japanese fonts.
4655 if (c
> 31 && c
!= 127)
4656 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
4658 if(!child_font
->font
)
4659 if(!load_child_font(font
, child_font
))
4662 if(!child_font
->font
->ft_face
)
4664 g
= get_glyph_index(child_font
->font
, c
);
4668 *linked_font
= child_font
->font
;
4675 /*************************************************************
4676 * WineEngGetCharWidth
4679 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4684 FT_UInt glyph_index
;
4685 GdiFont
*linked_font
;
4687 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4689 for(c
= firstChar
; c
<= lastChar
; c
++) {
4690 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4691 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4692 &gm
, 0, NULL
, NULL
);
4693 buffer
[c
- firstChar
] = linked_font
->gm
[glyph_index
].adv
;
4698 /*************************************************************
4699 * WineEngGetCharABCWidths
4702 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4707 FT_UInt glyph_index
;
4708 GdiFont
*linked_font
;
4710 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4712 if(!FT_IS_SCALABLE(font
->ft_face
))
4715 for(c
= firstChar
; c
<= lastChar
; c
++) {
4716 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4717 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4718 &gm
, 0, NULL
, NULL
);
4719 buffer
[c
- firstChar
].abcA
= linked_font
->gm
[glyph_index
].lsb
;
4720 buffer
[c
- firstChar
].abcB
= linked_font
->gm
[glyph_index
].bbx
;
4721 buffer
[c
- firstChar
].abcC
= linked_font
->gm
[glyph_index
].adv
- linked_font
->gm
[glyph_index
].lsb
-
4722 linked_font
->gm
[glyph_index
].bbx
;
4727 /*************************************************************
4728 * WineEngGetCharABCWidthsI
4731 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4736 FT_UInt glyph_index
;
4737 GdiFont
*linked_font
;
4739 if(!FT_IS_SCALABLE(font
->ft_face
))
4742 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
4744 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
4745 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4746 &gm
, 0, NULL
, NULL
);
4747 buffer
[c
- firstChar
].abcA
= linked_font
->gm
[c
].lsb
;
4748 buffer
[c
- firstChar
].abcB
= linked_font
->gm
[c
].bbx
;
4749 buffer
[c
- firstChar
].abcC
= linked_font
->gm
[c
].adv
- linked_font
->gm
[c
].lsb
4750 - linked_font
->gm
[c
].bbx
;
4753 for(c
= 0; c
< count
; c
++) {
4754 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4755 &gm
, 0, NULL
, NULL
);
4756 buffer
[c
].abcA
= linked_font
->gm
[pgi
[c
]].lsb
;
4757 buffer
[c
].abcB
= linked_font
->gm
[pgi
[c
]].bbx
;
4758 buffer
[c
].abcC
= linked_font
->gm
[pgi
[c
]].adv
4759 - linked_font
->gm
[pgi
[c
]].lsb
- linked_font
->gm
[pgi
[c
]].bbx
;
4765 /*************************************************************
4766 * WineEngGetTextExtentExPoint
4769 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4770 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4776 FT_UInt glyph_index
;
4777 GdiFont
*linked_font
;
4779 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
4783 WineEngGetTextMetrics(font
, &tm
);
4784 size
->cy
= tm
.tmHeight
;
4786 for(idx
= 0; idx
< count
; idx
++) {
4787 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
4788 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4789 &gm
, 0, NULL
, NULL
);
4790 size
->cx
+= linked_font
->gm
[glyph_index
].adv
;
4792 if (! pnfit
|| ext
<= max_ext
) {
4802 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4806 /*************************************************************
4807 * WineEngGetTextExtentPointI
4810 BOOL
WineEngGetTextExtentPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4817 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
4820 WineEngGetTextMetrics(font
, &tm
);
4821 size
->cy
= tm
.tmHeight
;
4823 for(idx
= 0; idx
< count
; idx
++) {
4824 WineEngGetGlyphOutline(font
, indices
[idx
],
4825 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
4827 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
4829 TRACE("return %d,%d\n", size
->cx
, size
->cy
);
4833 /*************************************************************
4834 * WineEngGetFontData
4837 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4840 FT_Face ft_face
= font
->ft_face
;
4844 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
4845 font
, table
, offset
, buf
, cbData
);
4847 if(!FT_IS_SFNT(ft_face
))
4855 if(table
) { /* MS tags differ in endidness from FT ones */
4856 table
= table
>> 24 | table
<< 24 |
4857 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
4860 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4861 if(pFT_Load_Sfnt_Table
) {
4862 /* make sure value of len is the value freetype says it needs */
4864 FT_ULong needed
= 0;
4865 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4866 if( !err
&& needed
< len
) len
= needed
;
4868 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4870 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4871 else { /* Do it the hard way */
4872 TT_Face tt_face
= (TT_Face
) ft_face
;
4873 SFNT_Interface
*sfnt
;
4874 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
4877 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
4881 /* A field was added in the middle of the structure in 2.1.x */
4882 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
4884 /* make sure value of len is the value freetype says it needs */
4886 FT_ULong needed
= 0;
4887 err
= sfnt
->load_any(tt_face
, table
, offset
, NULL
, &needed
);
4888 if( !err
&& needed
< len
) len
= needed
;
4890 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
4896 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4897 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4898 "Please upgrade your freetype library.\n");
4901 err
= FT_Err_Unimplemented_Feature
;
4905 TRACE("Can't find table %08x.\n", table
);
4911 /*************************************************************
4912 * WineEngGetTextFace
4915 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4918 lstrcpynW(str
, font
->name
, count
);
4919 return strlenW(font
->name
);
4921 return strlenW(font
->name
) + 1;
4924 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4926 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
4927 return font
->charset
;
4930 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4932 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
4933 struct list
*first_hfont
;
4936 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
4937 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
4938 if(font
== linked_font
)
4939 *new_hfont
= dc
->hFont
;
4942 first_hfont
= list_head(&linked_font
->hfontlist
);
4943 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
4949 /* Retrieve a list of supported Unicode ranges for a given font.
4950 * Can be called with NULL gs to calculate the buffer size. Returns
4951 * the number of ranges found.
4953 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
4955 DWORD num_ranges
= 0;
4957 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4960 FT_ULong char_code
, char_code_prev
;
4963 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
4965 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4966 face
->num_glyphs
, glyph_code
, char_code
);
4968 if (!glyph_code
) return 0;
4972 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4973 gs
->ranges
[0].cGlyphs
= 0;
4974 gs
->cGlyphsSupported
= 0;
4980 if (char_code
< char_code_prev
)
4982 ERR("expected increasing char code from FT_Get_Next_Char\n");
4985 if (char_code
- char_code_prev
> 1)
4990 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4991 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4992 gs
->cGlyphsSupported
++;
4997 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4998 gs
->cGlyphsSupported
++;
5000 char_code_prev
= char_code
;
5001 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
5005 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
5010 DWORD
WineEngGetFontUnicodeRanges(HDC hdc
, LPGLYPHSET glyphset
)
5013 DC
*dc
= DC_GetDCPtr(hdc
);
5015 TRACE("(%p, %p)\n", hdc
, glyphset
);
5021 DWORD num_ranges
= get_font_unicode_ranges(dc
->gdiFont
->ft_face
, glyphset
);
5023 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
5026 glyphset
->cbThis
= size
;
5027 glyphset
->cRanges
= num_ranges
;
5031 GDI_ReleaseObj(hdc
);
5035 /*************************************************************
5038 BOOL WINAPI
FontIsLinked(HDC hdc
)
5040 DC
*dc
= DC_GetDCPtr(hdc
);
5043 if(!dc
) return FALSE
;
5044 if(dc
->gdiFont
&& !list_empty(&dc
->gdiFont
->child_fonts
))
5046 GDI_ReleaseObj(hdc
);
5047 TRACE("returning %d\n", ret
);
5051 static BOOL
is_hinting_enabled(void)
5053 /* Use the >= 2.2.0 function if available */
5054 if(pFT_Get_TrueType_Engine_Type
)
5056 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
5057 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
5059 #ifdef FT_DRIVER_HAS_HINTER
5064 /* otherwise if we've been compiled with < 2.2.0 headers
5065 use the internal macro */
5066 mod
= pFT_Get_Module(library
, "truetype");
5067 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
5075 /*************************************************************************
5076 * GetRasterizerCaps (GDI32.@)
5078 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5080 static int hinting
= -1;
5084 hinting
= is_hinting_enabled();
5085 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
5088 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5089 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
5090 lprs
->nLanguageID
= 0;
5094 /*************************************************************************
5095 * Kerning support for TrueType fonts
5097 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5099 struct TT_kern_table
5105 struct TT_kern_subtable
5114 USHORT horizontal
: 1;
5116 USHORT cross_stream
: 1;
5117 USHORT override
: 1;
5118 USHORT reserved1
: 4;
5124 struct TT_format0_kern_subtable
5128 USHORT entrySelector
;
5139 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
5140 const struct TT_format0_kern_subtable
*tt_f0_ks
,
5141 const USHORT
*glyph_to_char
,
5142 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
5145 const struct TT_kern_pair
*tt_kern_pair
;
5147 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
5149 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
5151 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5152 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
5153 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
5155 if (!kern_pair
|| !cPairs
)
5158 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
5160 nPairs
= min(nPairs
, cPairs
);
5162 for (i
= 0; i
< nPairs
; i
++)
5164 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
5165 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
5166 /* this algorithm appears to better match what Windows does */
5167 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
5168 if (kern_pair
->iKernAmount
< 0)
5170 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
5171 kern_pair
->iKernAmount
-= font
->ppem
;
5173 else if (kern_pair
->iKernAmount
> 0)
5175 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
5176 kern_pair
->iKernAmount
+= font
->ppem
;
5178 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
5180 TRACE("left %u right %u value %d\n",
5181 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
5185 TRACE("copied %u entries\n", nPairs
);
5189 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5193 const struct TT_kern_table
*tt_kern_table
;
5194 const struct TT_kern_subtable
*tt_kern_subtable
;
5196 USHORT
*glyph_to_char
;
5198 if (font
->total_kern_pairs
!= (DWORD
)-1)
5200 if (cPairs
&& kern_pair
)
5202 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5203 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5206 return font
->total_kern_pairs
;
5209 font
->total_kern_pairs
= 0;
5211 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
5213 if (length
== GDI_ERROR
)
5215 TRACE("no kerning data in the font\n");
5219 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
5222 WARN("Out of memory\n");
5226 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
5228 /* build a glyph index to char code map */
5229 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
5232 WARN("Out of memory allocating a glyph index to char code map\n");
5233 HeapFree(GetProcessHeap(), 0, buf
);
5237 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5243 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
5245 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5246 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
5250 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5252 /* FIXME: This doesn't match what Windows does: it does some fancy
5253 * things with duplicate glyph index to char code mappings, while
5254 * we just avoid overriding existing entries.
5256 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
5257 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
5259 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
5266 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
5267 for (n
= 0; n
<= 65535; n
++)
5268 glyph_to_char
[n
] = (USHORT
)n
;
5271 tt_kern_table
= buf
;
5272 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
5273 TRACE("version %u, nTables %u\n",
5274 GET_BE_WORD(tt_kern_table
->version
), nTables
);
5276 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
5278 for (i
= 0; i
< nTables
; i
++)
5280 struct TT_kern_subtable tt_kern_subtable_copy
;
5282 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
5283 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
5284 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
5286 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5287 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
5288 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
5290 /* According to the TrueType specification this is the only format
5291 * that will be properly interpreted by Windows and OS/2
5293 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
5295 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
5297 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5298 glyph_to_char
, NULL
, 0);
5299 font
->total_kern_pairs
+= new_chunk
;
5301 if (!font
->kern_pairs
)
5302 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
5303 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5305 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
5306 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5308 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5309 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
5312 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
5314 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
5317 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
5318 HeapFree(GetProcessHeap(), 0, buf
);
5320 if (cPairs
&& kern_pair
)
5322 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5323 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5326 return font
->total_kern_pairs
;
5329 #else /* HAVE_FREETYPE */
5331 /*************************************************************************/
5333 BOOL
WineEngInit(void)
5337 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
5341 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
5346 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5351 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
5352 LPWORD pgi
, DWORD flags
)
5357 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
5358 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5361 ERR("called but we don't have FreeType\n");
5365 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5367 ERR("called but we don't have FreeType\n");
5371 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5372 OUTLINETEXTMETRICW
*potm
)
5374 ERR("called but we don't have FreeType\n");
5378 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5381 ERR("called but we don't have FreeType\n");
5385 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5388 ERR("called but we don't have FreeType\n");
5392 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5395 ERR("called but we don't have FreeType\n");
5399 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5400 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5402 ERR("called but we don't have FreeType\n");
5406 BOOL
WineEngGetTextExtentPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5409 ERR("called but we don't have FreeType\n");
5413 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5416 ERR("called but we don't have FreeType\n");
5420 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5422 ERR("called but we don't have FreeType\n");
5426 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5432 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5438 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5441 return DEFAULT_CHARSET
;
5444 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5449 DWORD
WineEngGetFontUnicodeRanges(HDC hdc
, LPGLYPHSET glyphset
)
5451 FIXME("(%p, %p): stub\n", hdc
, glyphset
);
5455 BOOL WINAPI
FontIsLinked(HDC hdc
)
5460 /*************************************************************************
5461 * GetRasterizerCaps (GDI32.@)
5463 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5465 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5467 lprs
->nLanguageID
= 0;
5471 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5473 ERR("called but we don't have FreeType\n");
5477 #endif /* HAVE_FREETYPE */