2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
60 #undef GetCurrentThread
63 #undef GetCurrentProcess
76 #endif /* HAVE_CARBON_CARBON_H */
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font
);
93 #ifdef HAVE_FT2BUILD_H
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType
;
143 static FT_Library library
= 0;
150 static FT_Version_t FT_Version
;
151 static DWORD FT_SimpleVersion
;
153 static void *ft_handle
= NULL
;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit
);
157 MAKE_FUNCPTR(FT_Done_Face
);
158 MAKE_FUNCPTR(FT_Get_Char_Index
);
159 MAKE_FUNCPTR(FT_Get_Module
);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
163 MAKE_FUNCPTR(FT_Init_FreeType
);
164 MAKE_FUNCPTR(FT_Load_Glyph
);
165 MAKE_FUNCPTR(FT_Matrix_Multiply
);
166 MAKE_FUNCPTR(FT_MulFix
);
167 MAKE_FUNCPTR(FT_New_Face
);
168 MAKE_FUNCPTR(FT_New_Memory_Face
);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
170 MAKE_FUNCPTR(FT_Outline_Transform
);
171 MAKE_FUNCPTR(FT_Outline_Translate
);
172 MAKE_FUNCPTR(FT_Select_Charmap
);
173 MAKE_FUNCPTR(FT_Set_Charmap
);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
175 MAKE_FUNCPTR(FT_Vector_Transform
);
176 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
177 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
178 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
179 static FT_ULong (*pFT_Get_Next_Char
)(FT_Face
,FT_ULong
,FT_UInt
*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent
);
188 MAKE_FUNCPTR(FcFontList
);
189 MAKE_FUNCPTR(FcFontSetDestroy
);
190 MAKE_FUNCPTR(FcInit
);
191 MAKE_FUNCPTR(FcObjectSetAdd
);
192 MAKE_FUNCPTR(FcObjectSetCreate
);
193 MAKE_FUNCPTR(FcObjectSetDestroy
);
194 MAKE_FUNCPTR(FcPatternCreate
);
195 MAKE_FUNCPTR(FcPatternDestroy
);
196 MAKE_FUNCPTR(FcPatternGetBool
);
197 MAKE_FUNCPTR(FcPatternGetString
);
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
227 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
234 FT_Short internal_leading
;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
241 FT_Short height
, width
;
242 FT_Pos size
, x_ppem
, y_ppem
;
245 typedef struct tagFace
{
250 DWORD font_data_size
;
255 FONTSIGNATURE fs_links
;
256 DWORD ntmFlags
; /* Only some bits stored here. Others are computed on the fly */
257 FT_Fixed font_version
;
259 Bitmap_Size size
; /* set if face is a bitmap */
260 BOOL external
; /* TRUE if we should manually add this font to the registry */
261 struct tagFamily
*family
;
264 typedef struct tagFamily
{
266 const WCHAR
*FamilyName
;
272 INT adv
; /* These three hold to widths of the unrotated chars */
290 typedef struct tagHFONTLIST
{
304 struct font_mapping
*mapping
;
315 struct list hfontlist
;
320 OUTLINETEXTMETRICW
*potm
;
322 DWORD total_kern_pairs
;
323 KERNINGPAIR
*kern_pairs
;
326 struct list child_fonts
;
332 const WCHAR
*font_name
;
336 #define GM_BLOCK_SIZE 128
337 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
339 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
340 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
341 #define UNUSED_CACHE_SIZE 10
342 static struct list child_font_list
= LIST_INIT(child_font_list
);
343 static struct list system_links
= LIST_INIT(system_links
);
345 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
347 static struct list font_list
= LIST_INIT(font_list
);
349 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
350 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
351 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
353 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
355 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
356 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
357 'W','i','n','d','o','w','s','\\',
358 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
359 'F','o','n','t','s','\0'};
361 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
362 'W','i','n','d','o','w','s',' ','N','T','\\',
363 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
364 'F','o','n','t','s','\0'};
366 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
367 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
368 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
369 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
371 static const WCHAR
* const SystemFontValues
[4] = {
378 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
379 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
381 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
382 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
383 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
384 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
385 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
386 'E','u','r','o','p','e','a','n','\0'};
387 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
388 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
389 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
390 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
391 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
392 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
393 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
394 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
395 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
396 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
397 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
398 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
400 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
410 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
418 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
427 typedef struct tagFontSubst
{
443 static struct list mappings_list
= LIST_INIT( mappings_list
);
445 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
447 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
449 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
451 /****************************************
452 * Notes on .fon files
454 * The fonts System, FixedSys and Terminal are special. There are typically multiple
455 * versions installed for different resolutions and codepages. Windows stores which one to use
456 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
458 * FIXEDFON.FON FixedSys
460 * OEMFONT.FON Terminal
461 * LogPixels Current dpi set by the display control panel applet
462 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
463 * also has a LogPixels value that appears to mirror this)
465 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
466 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
467 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
468 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
469 * so that makes sense.
471 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
472 * to be mapped into the registry on Windows 2000 at least).
475 * ega80woa.fon=ega80850.fon
476 * ega40woa.fon=ega40850.fon
477 * cga80woa.fon=cga80850.fon
478 * cga40woa.fon=cga40850.fon
481 #ifdef HAVE_CARBON_CARBON_H
482 static char *find_cache_dir(void)
486 static char cached_path
[MAX_PATH
];
487 static const char *wine
= "/Wine", *fonts
= "/Fonts";
489 if(*cached_path
) return cached_path
;
491 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
494 WARN("can't create cached data folder\n");
497 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
500 WARN("can't create cached data path\n");
504 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
506 ERR("Could not create full path\n");
510 strcat(cached_path
, wine
);
512 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
514 WARN("Couldn't mkdir %s\n", cached_path
);
518 strcat(cached_path
, fonts
);
519 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
521 WARN("Couldn't mkdir %s\n", cached_path
);
528 /******************************************************************
531 * Extracts individual TrueType font files from a Mac suitcase font
532 * and saves them into the user's caches directory (see
534 * Returns a NULL terminated array of filenames.
536 * We do this because they are apps that try to read ttf files
537 * themselves and they don't like Mac suitcase files.
539 static char **expand_mac_font(const char *path
)
546 const char *filename
;
550 unsigned int size
, max_size
;
553 TRACE("path %s\n", path
);
555 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
558 WARN("failed to get ref\n");
562 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
565 TRACE("no data fork, so trying resource fork\n");
566 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
569 TRACE("unable to open resource fork\n");
576 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
579 CloseResFile(res_ref
);
583 out_dir
= find_cache_dir();
585 filename
= strrchr(path
, '/');
586 if(!filename
) filename
= path
;
589 /* output filename has the form out_dir/filename_%04x.ttf */
590 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
597 unsigned short *num_faces_ptr
, num_faces
, face
;
600 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
602 fond
= Get1IndResource(fond_res
, idx
);
604 TRACE("got fond resource %d\n", idx
);
607 fam_rec
= *(FamRec
**)fond
;
608 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
609 num_faces
= GET_BE_WORD(*num_faces_ptr
);
611 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
612 TRACE("num faces %04x\n", num_faces
);
613 for(face
= 0; face
< num_faces
; face
++, assoc
++)
616 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
617 unsigned short size
, font_id
;
620 size
= GET_BE_WORD(assoc
->fontSize
);
621 font_id
= GET_BE_WORD(assoc
->fontID
);
624 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
628 TRACE("trying to load sfnt id %04x\n", font_id
);
629 sfnt
= GetResource(sfnt_res
, font_id
);
632 TRACE("can't get sfnt resource %04x\n", font_id
);
636 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
641 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
643 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
644 if(fd
!= -1 || errno
== EEXIST
)
648 unsigned char *sfnt_data
;
651 sfnt_data
= *(unsigned char**)sfnt
;
652 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
656 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
659 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
661 ret
.array
[ret
.size
++] = output
;
665 WARN("unable to create %s\n", output
);
666 HeapFree(GetProcessHeap(), 0, output
);
669 ReleaseResource(sfnt
);
672 ReleaseResource(fond
);
675 CloseResFile(res_ref
);
680 #endif /* HAVE_CARBON_CARBON_H */
682 static inline BOOL
is_win9x(void)
684 return GetVersion() & 0x80000000;
687 This function builds an FT_Fixed from a float. It puts the integer part
688 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
689 It fails if the integer part of the float number is greater than SHORT_MAX.
691 static inline FT_Fixed
FT_FixedFromFloat(float f
)
694 unsigned short fract
= (f
- value
) * 0xFFFF;
695 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
699 This function builds an FT_Fixed from a FIXED. It simply put f.value
700 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
702 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
704 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
708 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
713 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
714 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
716 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
717 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
719 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
721 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
723 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
727 file
= strrchr(face
->file
, '/');
732 if(!strcasecmp(file
, file_nameA
))
734 HeapFree(GetProcessHeap(), 0, file_nameA
);
739 HeapFree(GetProcessHeap(), 0, file_nameA
);
743 static Family
*find_family_from_name(const WCHAR
*name
)
747 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
749 if(!strcmpiW(family
->FamilyName
, name
))
756 static void DumpSubstList(void)
760 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
762 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
763 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
764 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
766 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
767 debugstr_w(psub
->to
.name
));
772 static LPWSTR
strdupW(LPCWSTR p
)
775 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
776 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
781 static LPSTR
strdupA(LPCSTR p
)
784 DWORD len
= (strlen(p
) + 1);
785 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
790 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
795 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
797 if(!strcmpiW(element
->from
.name
, from_name
) &&
798 (element
->from
.charset
== from_charset
||
799 element
->from
.charset
== -1))
806 #define ADD_FONT_SUBST_FORCE 1
808 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
810 FontSubst
*from_exist
, *to_exist
;
812 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
814 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
816 list_remove(&from_exist
->entry
);
817 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
818 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
819 HeapFree(GetProcessHeap(), 0, from_exist
);
825 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
829 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
830 subst
->to
.name
= strdupW(to_exist
->to
.name
);
833 list_add_tail(subst_list
, &subst
->entry
);
838 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
839 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
840 HeapFree(GetProcessHeap(), 0, subst
);
844 static void split_subst_info(NameCs
*nc
, LPSTR str
)
846 CHAR
*p
= strrchr(str
, ',');
851 nc
->charset
= strtol(p
+1, NULL
, 10);
854 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
855 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
856 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
859 static void LoadSubstList(void)
863 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
867 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
868 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
869 &hkey
) == ERROR_SUCCESS
) {
871 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
872 &valuelen
, &datalen
, NULL
, NULL
);
874 valuelen
++; /* returned value doesn't include room for '\0' */
875 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
876 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
880 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
881 &dlen
) == ERROR_SUCCESS
) {
882 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
884 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
885 split_subst_info(&psub
->from
, value
);
886 split_subst_info(&psub
->to
, data
);
888 /* Win 2000 doesn't allow mapping between different charsets
889 or mapping of DEFAULT_CHARSET */
890 if((psub
->to
.charset
!= psub
->from
.charset
) ||
891 psub
->to
.charset
== DEFAULT_CHARSET
) {
892 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
893 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
894 HeapFree(GetProcessHeap(), 0, psub
);
896 add_font_subst(&font_subst_list
, psub
, 0);
898 /* reset dlen and vlen */
902 HeapFree(GetProcessHeap(), 0, data
);
903 HeapFree(GetProcessHeap(), 0, value
);
908 static WCHAR
*get_familyname(FT_Face ft_face
)
910 WCHAR
*family
= NULL
;
912 FT_UInt num_names
, name_index
, i
;
914 if(FT_IS_SFNT(ft_face
))
916 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
918 for(name_index
= 0; name_index
< num_names
; name_index
++)
920 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
922 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
923 (name
.language_id
== GetUserDefaultLCID()) &&
924 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
925 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
927 /* String is not nul terminated and string_len is a byte length. */
928 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
929 for(i
= 0; i
< name
.string_len
/ 2; i
++)
931 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
932 family
[i
] = GET_BE_WORD(*tmp
);
936 TRACE("Got localised name %s\n", debugstr_w(family
));
947 #define ADDFONT_EXTERNAL_FONT 0x01
948 #define ADDFONT_FORCE_BITMAP 0x02
949 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
953 TT_Header
*pHeader
= NULL
;
954 WCHAR
*english_family
, *localised_family
, *StyleW
;
958 struct list
*family_elem_ptr
, *face_elem_ptr
;
960 FT_Long face_index
= 0, num_faces
;
961 #ifdef HAVE_FREETYPE_FTWINFNT_H
962 FT_WinFNT_HeaderRec winfnt_header
;
964 int i
, bitmap_num
, internal_leading
;
967 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
968 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
970 #ifdef HAVE_CARBON_CARBON_H
971 if(file
&& !fake_family
)
973 char **mac_list
= expand_mac_font(file
);
976 BOOL had_one
= FALSE
;
978 for(cursor
= mac_list
; *cursor
; cursor
++)
981 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
982 HeapFree(GetProcessHeap(), 0, *cursor
);
984 HeapFree(GetProcessHeap(), 0, mac_list
);
989 #endif /* HAVE_CARBON_CARBON_H */
992 char *family_name
= fake_family
;
996 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
997 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1000 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1001 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1005 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1009 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*/
1010 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1011 pFT_Done_Face(ft_face
);
1015 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1016 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1017 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1018 pFT_Done_Face(ft_face
);
1022 if(FT_IS_SFNT(ft_face
) && (!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
1023 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1024 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))) {
1025 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1026 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1027 pFT_Done_Face(ft_face
);
1031 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1032 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1033 pFT_Done_Face(ft_face
);
1039 localised_family
= get_familyname(ft_face
);
1040 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1042 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1043 HeapFree(GetProcessHeap(), 0, localised_family
);
1044 num_faces
= ft_face
->num_faces
;
1045 pFT_Done_Face(ft_face
);
1048 HeapFree(GetProcessHeap(), 0, localised_family
);
1052 family_name
= ft_face
->family_name
;
1056 My_FT_Bitmap_Size
*size
= NULL
;
1059 if(!FT_IS_SCALABLE(ft_face
))
1060 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1062 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1063 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1064 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1066 localised_family
= NULL
;
1068 localised_family
= get_familyname(ft_face
);
1069 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1070 HeapFree(GetProcessHeap(), 0, localised_family
);
1071 localised_family
= NULL
;
1076 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1077 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1078 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1083 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1084 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1085 list_init(&family
->faces
);
1086 list_add_tail(&font_list
, &family
->entry
);
1088 if(localised_family
) {
1089 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1090 subst
->from
.name
= strdupW(english_family
);
1091 subst
->from
.charset
= -1;
1092 subst
->to
.name
= strdupW(localised_family
);
1093 subst
->to
.charset
= -1;
1094 add_font_subst(&font_subst_list
, subst
, 0);
1097 HeapFree(GetProcessHeap(), 0, localised_family
);
1098 HeapFree(GetProcessHeap(), 0, english_family
);
1100 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1101 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1102 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1104 internal_leading
= 0;
1105 memset(&fs
, 0, sizeof(fs
));
1107 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1109 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1110 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1111 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1112 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1113 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1114 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1115 if(pOS2
->version
== 0) {
1118 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1121 fs
.fsCsb
[0] |= 1L << 31;
1124 #ifdef HAVE_FREETYPE_FTWINFNT_H
1125 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1127 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1128 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1129 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1130 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
1131 internal_leading
= winfnt_header
.internal_leading
;
1135 face_elem_ptr
= list_head(&family
->faces
);
1136 while(face_elem_ptr
) {
1137 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1138 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1139 if(!strcmpW(face
->StyleName
, StyleW
) &&
1140 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1141 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1142 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1143 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1146 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1147 HeapFree(GetProcessHeap(), 0, StyleW
);
1148 pFT_Done_Face(ft_face
);
1151 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1152 TRACE("Original font is newer so skipping this one\n");
1153 HeapFree(GetProcessHeap(), 0, StyleW
);
1154 pFT_Done_Face(ft_face
);
1157 TRACE("Replacing original with this one\n");
1158 list_remove(&face
->entry
);
1159 HeapFree(GetProcessHeap(), 0, face
->file
);
1160 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1161 HeapFree(GetProcessHeap(), 0, face
);
1166 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1167 list_add_tail(&family
->faces
, &face
->entry
);
1168 face
->StyleName
= StyleW
;
1171 face
->file
= strdupA(file
);
1172 face
->font_data_ptr
= NULL
;
1173 face
->font_data_size
= 0;
1178 face
->font_data_ptr
= font_data_ptr
;
1179 face
->font_data_size
= font_data_size
;
1181 face
->face_index
= face_index
;
1182 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
1183 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
1184 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1185 face
->family
= family
;
1186 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1187 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
1188 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1190 if(FT_IS_SCALABLE(ft_face
)) {
1191 memset(&face
->size
, 0, sizeof(face
->size
));
1192 face
->scalable
= TRUE
;
1194 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1195 size
->height
, size
->width
, size
->size
>> 6,
1196 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1197 face
->size
.height
= size
->height
;
1198 face
->size
.width
= size
->width
;
1199 face
->size
.size
= size
->size
;
1200 face
->size
.x_ppem
= size
->x_ppem
;
1201 face
->size
.y_ppem
= size
->y_ppem
;
1202 face
->size
.internal_leading
= internal_leading
;
1203 face
->scalable
= FALSE
;
1206 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1208 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1210 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1211 face
->ntmFlags
= NTM_PS_OPENTYPE
;
1216 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1217 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1218 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1219 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1222 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1223 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1224 switch(ft_face
->charmaps
[i
]->encoding
) {
1225 case FT_ENCODING_UNICODE
:
1226 case FT_ENCODING_APPLE_ROMAN
:
1227 face
->fs
.fsCsb
[0] |= 1;
1229 case FT_ENCODING_MS_SYMBOL
:
1230 face
->fs
.fsCsb
[0] |= 1L << 31;
1238 if(face
->fs
.fsCsb
[0] & ~(1L << 31))
1239 have_installed_roman_font
= TRUE
;
1240 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1242 num_faces
= ft_face
->num_faces
;
1243 pFT_Done_Face(ft_face
);
1244 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1245 debugstr_w(StyleW
));
1246 } while(num_faces
> ++face_index
);
1250 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1252 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1255 static void DumpFontList(void)
1259 struct list
*family_elem_ptr
, *face_elem_ptr
;
1261 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1262 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1263 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1264 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1265 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1266 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1268 TRACE(" %d", face
->size
.height
);
1275 /***********************************************************
1276 * The replacement list is a way to map an entire font
1277 * family onto another family. For example adding
1279 * [HKCU\Software\Wine\Fonts\Replacements]
1280 * "Wingdings"="Winedings"
1282 * would enumerate the Winedings font both as Winedings and
1283 * Wingdings. However if a real Wingdings font is present the
1284 * replacement does not take place.
1287 static void LoadReplaceList(void)
1290 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1295 struct list
*family_elem_ptr
, *face_elem_ptr
;
1298 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1299 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1301 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1302 &valuelen
, &datalen
, NULL
, NULL
);
1304 valuelen
++; /* returned value doesn't include room for '\0' */
1305 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1306 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1310 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1311 &dlen
) == ERROR_SUCCESS
) {
1312 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1313 /* "NewName"="Oldname" */
1314 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1316 /* Find the old family and hence all of the font files
1318 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1319 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1320 if(!strcmpiW(family
->FamilyName
, data
)) {
1321 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1322 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1323 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1324 debugstr_w(face
->StyleName
), familyA
);
1325 /* Now add a new entry with the new family name */
1326 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1331 /* reset dlen and vlen */
1335 HeapFree(GetProcessHeap(), 0, data
);
1336 HeapFree(GetProcessHeap(), 0, value
);
1341 /*************************************************************
1344 static BOOL
init_system_links(void)
1346 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1347 'W','i','n','d','o','w','s',' ','N','T','\\',
1348 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1349 'S','y','s','t','e','m','L','i','n','k',0};
1352 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1353 WCHAR
*value
, *data
;
1354 WCHAR
*entry
, *next
;
1355 SYSTEM_LINKS
*font_link
, *system_font_link
;
1356 CHILD_FONT
*child_font
;
1357 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1358 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1359 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1365 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1367 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1368 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1369 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1370 val_len
= max_val
+ 1;
1371 data_len
= max_data
;
1373 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1375 TRACE("%s:\n", debugstr_w(value
));
1377 memset(&fs
, 0, sizeof(fs
));
1378 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1379 psub
= get_font_subst(&font_subst_list
, value
, -1);
1380 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1381 list_init(&font_link
->links
);
1382 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1385 CHILD_FONT
*child_font
;
1387 TRACE("\t%s\n", debugstr_w(entry
));
1389 next
= entry
+ strlenW(entry
) + 1;
1391 face_name
= strchrW(entry
, ',');
1395 while(isspaceW(*face_name
))
1398 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1400 face_name
= psub
->to
.name
;
1402 face
= find_face_from_filename(entry
, face_name
);
1405 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1409 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1410 child_font
->face
= face
;
1411 child_font
->font
= NULL
;
1412 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1413 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1414 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1415 list_add_tail(&font_link
->links
, &child_font
->entry
);
1417 family
= find_family_from_name(font_link
->font_name
);
1420 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1422 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
1425 list_add_tail(&system_links
, &font_link
->entry
);
1426 val_len
= max_val
+ 1;
1427 data_len
= max_data
;
1430 HeapFree(GetProcessHeap(), 0, value
);
1431 HeapFree(GetProcessHeap(), 0, data
);
1435 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1438 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1439 system_font_link
->font_name
= strdupW(System
);
1440 list_init(&system_font_link
->links
);
1442 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1445 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1446 child_font
->face
= face
;
1447 child_font
->font
= NULL
;
1448 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1449 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1451 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1453 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1455 CHILD_FONT
*font_link_entry
;
1456 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1458 CHILD_FONT
*new_child
;
1459 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1460 new_child
->face
= font_link_entry
->face
;
1461 new_child
->font
= NULL
;
1462 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1467 list_add_tail(&system_links
, &system_font_link
->entry
);
1471 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1474 struct dirent
*dent
;
1475 char path
[MAX_PATH
];
1477 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1479 dir
= opendir(dirname
);
1481 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1484 while((dent
= readdir(dir
)) != NULL
) {
1485 struct stat statbuf
;
1487 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1490 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1492 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1494 if(stat(path
, &statbuf
) == -1)
1496 WARN("Can't stat %s\n", debugstr_a(path
));
1499 if(S_ISDIR(statbuf
.st_mode
))
1500 ReadFontDir(path
, external_fonts
);
1502 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1508 static void load_fontconfig_fonts(void)
1510 #ifdef SONAME_LIBFONTCONFIG
1511 void *fc_handle
= NULL
;
1520 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1522 TRACE("Wine cannot find the fontconfig library (%s).\n",
1523 SONAME_LIBFONTCONFIG
);
1526 #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;}
1527 LOAD_FUNCPTR(FcConfigGetCurrent
);
1528 LOAD_FUNCPTR(FcFontList
);
1529 LOAD_FUNCPTR(FcFontSetDestroy
);
1530 LOAD_FUNCPTR(FcInit
);
1531 LOAD_FUNCPTR(FcObjectSetAdd
);
1532 LOAD_FUNCPTR(FcObjectSetCreate
);
1533 LOAD_FUNCPTR(FcObjectSetDestroy
);
1534 LOAD_FUNCPTR(FcPatternCreate
);
1535 LOAD_FUNCPTR(FcPatternDestroy
);
1536 LOAD_FUNCPTR(FcPatternGetBool
);
1537 LOAD_FUNCPTR(FcPatternGetString
);
1540 if(!pFcInit()) return;
1542 config
= pFcConfigGetCurrent();
1543 pat
= pFcPatternCreate();
1544 os
= pFcObjectSetCreate();
1545 pFcObjectSetAdd(os
, FC_FILE
);
1546 pFcObjectSetAdd(os
, FC_SCALABLE
);
1547 fontset
= pFcFontList(config
, pat
, os
);
1548 if(!fontset
) return;
1549 for(i
= 0; i
< fontset
->nfont
; i
++) {
1552 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1554 TRACE("fontconfig: %s\n", file
);
1556 /* We're just interested in OT/TT fonts for now, so this hack just
1557 picks up the scalable fonts without extensions .pf[ab] to save time
1558 loading every other font */
1560 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1562 TRACE("not scalable\n");
1566 len
= strlen( file
);
1567 if(len
< 4) continue;
1568 ext
= &file
[ len
- 3 ];
1569 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1570 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1572 pFcFontSetDestroy(fontset
);
1573 pFcObjectSetDestroy(os
);
1574 pFcPatternDestroy(pat
);
1580 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1583 const char *data_dir
= wine_get_data_dir();
1585 if (!data_dir
) data_dir
= wine_get_build_dir();
1592 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1594 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1596 strcpy(unix_name
, data_dir
);
1597 strcat(unix_name
, "/fonts/");
1599 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1601 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1602 HeapFree(GetProcessHeap(), 0, unix_name
);
1607 static void load_system_fonts(void)
1610 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1611 const WCHAR
* const *value
;
1613 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1616 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1617 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1618 strcatW(windowsdir
, fontsW
);
1619 for(value
= SystemFontValues
; *value
; value
++) {
1620 dlen
= sizeof(data
);
1621 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1625 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1626 if((unixname
= wine_get_unix_file_name(pathW
))) {
1627 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1628 HeapFree(GetProcessHeap(), 0, unixname
);
1631 load_font_from_data_dir(data
);
1638 /*************************************************************
1640 * This adds registry entries for any externally loaded fonts
1641 * (fonts from fontconfig or FontDirs). It also deletes entries
1642 * of no longer existing fonts.
1645 static void update_reg_entries(void)
1647 HKEY winkey
= 0, externalkey
= 0;
1650 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
1653 struct list
*family_elem_ptr
, *face_elem_ptr
;
1655 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1656 static const WCHAR spaceW
[] = {' ', '\0'};
1659 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1660 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
1661 ERR("Can't create Windows font reg key\n");
1664 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1665 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
1666 ERR("Can't create external font reg key\n");
1670 /* Delete all external fonts added last time */
1672 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1673 &valuelen
, &datalen
, NULL
, NULL
);
1674 valuelen
++; /* returned value doesn't include room for '\0' */
1675 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1676 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1678 dlen
= datalen
* sizeof(WCHAR
);
1681 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1682 &dlen
) == ERROR_SUCCESS
) {
1684 RegDeleteValueW(winkey
, valueW
);
1685 /* reset dlen and vlen */
1689 HeapFree(GetProcessHeap(), 0, data
);
1690 HeapFree(GetProcessHeap(), 0, valueW
);
1692 /* Delete the old external fonts key */
1693 RegCloseKey(externalkey
);
1695 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1697 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1698 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1699 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
1700 ERR("Can't create external font reg key\n");
1704 /* enumerate the fonts and add external ones to the two keys */
1706 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1707 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1708 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1709 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1710 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1711 if(!face
->external
) continue;
1713 if(strcmpiW(face
->StyleName
, RegularW
))
1714 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1715 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1716 strcpyW(valueW
, family
->FamilyName
);
1717 if(len
!= len_fam
) {
1718 strcatW(valueW
, spaceW
);
1719 strcatW(valueW
, face
->StyleName
);
1721 strcatW(valueW
, TrueType
);
1722 if((path
= strrchr(face
->file
, '/')) == NULL
)
1726 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1728 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1729 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1730 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1731 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1733 HeapFree(GetProcessHeap(), 0, file
);
1734 HeapFree(GetProcessHeap(), 0, valueW
);
1739 RegCloseKey(externalkey
);
1741 RegCloseKey(winkey
);
1746 /*************************************************************
1747 * WineEngAddFontResourceEx
1750 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1752 if (ft_handle
) /* do it only if we have freetype up and running */
1757 FIXME("Ignoring flags %x\n", flags
);
1759 if((unixname
= wine_get_unix_file_name(file
)))
1761 INT ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1762 HeapFree(GetProcessHeap(), 0, unixname
);
1769 /*************************************************************
1770 * WineEngAddFontMemResourceEx
1773 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
1775 if (ft_handle
) /* do it only if we have freetype up and running */
1777 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
1779 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
1780 memcpy(pFontCopy
, pbFont
, cbFont
);
1782 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1786 TRACE("AddFontToList failed\n");
1787 HeapFree(GetProcessHeap(), 0, pFontCopy
);
1790 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1791 * For now return something unique but quite random
1793 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
1794 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
1801 /*************************************************************
1802 * WineEngRemoveFontResourceEx
1805 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1811 static const struct nls_update_font_list
1813 UINT ansi_cp
, oem_cp
;
1814 const char *oem
, *fixed
, *system
;
1815 const char *courier
, *serif
, *small
, *sserif
;
1816 /* these are for font substitute */
1817 const char *shelldlg
, *tmsrmn
;
1818 } nls_update_font_list
[] =
1820 /* Latin 1 (United States) */
1821 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1822 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1823 "Tahoma","Times New Roman",
1825 /* Latin 1 (Multilingual) */
1826 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1827 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1828 "Tahoma","Times New Roman", /* FIXME unverified */
1830 /* Eastern Europe */
1831 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1832 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1833 "Tahoma","Times New Roman", /* FIXME unverified */
1836 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1837 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1838 "Tahoma","Times New Roman", /* FIXME unverified */
1841 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1842 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1843 "Tahoma","Times New Roman", /* FIXME unverified */
1846 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1847 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1848 "Tahoma","Times New Roman", /* FIXME unverified */
1851 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1852 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1853 "Tahoma","Times New Roman", /* FIXME unverified */
1856 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1857 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1858 "Tahoma","Times New Roman", /* FIXME unverified */
1861 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1862 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1863 "Tahoma","Times New Roman", /* FIXME unverified */
1866 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1867 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1868 "Tahoma","Times New Roman", /* FIXME unverified */
1871 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1872 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1873 "Tahoma","Times New Roman", /* FIXME unverified */
1876 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1877 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1878 "MS UI Gothic","MS Serif",
1880 /* Chinese Simplified */
1881 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1882 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1883 "Tahoma", "Times New Roman", /* FIXME unverified */
1886 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1887 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1890 /* Chinese Traditional */
1891 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1892 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1893 "Tahoma", "Times New Roman", /* FIXME unverified */
1897 static inline HKEY
create_fonts_NT_registry_key(void)
1901 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
1902 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1906 static inline HKEY
create_fonts_9x_registry_key(void)
1910 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
1911 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1915 static inline HKEY
create_config_fonts_registry_key(void)
1919 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
1920 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1924 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
1926 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
1927 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
1928 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
1929 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
1932 static void update_font_info(void)
1934 char buf
[40], cpbuf
[40];
1937 UINT i
, ansi_cp
= 0, oem_cp
= 0;
1939 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
1942 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1943 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
1944 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1945 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
1946 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
1949 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
1951 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
1956 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
1958 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
1960 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
1963 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
1965 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
1966 nls_update_font_list
[i
].oem_cp
== oem_cp
)
1970 hkey
= create_config_fonts_registry_key();
1971 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
1972 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
1973 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
1976 hkey
= create_fonts_NT_registry_key();
1977 add_font_list(hkey
, &nls_update_font_list
[i
]);
1980 hkey
= create_fonts_9x_registry_key();
1981 add_font_list(hkey
, &nls_update_font_list
[i
]);
1984 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
1986 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
1987 strlen(nls_update_font_list
[i
].shelldlg
)+1);
1988 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
1989 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
1995 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
1998 /*************************************************************
2001 * Initialize FreeType library and create a list of available faces
2003 BOOL
WineEngInit(void)
2005 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2006 static const WCHAR pathW
[] = {'P','a','t','h',0};
2008 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2010 WCHAR windowsdir
[MAX_PATH
];
2013 const char *data_dir
;
2017 /* update locale dependent font info in registry */
2020 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2023 "Wine cannot find the FreeType font library. To enable Wine to\n"
2024 "use TrueType fonts please install a version of FreeType greater than\n"
2025 "or equal to 2.0.5.\n"
2026 "http://www.freetype.org\n");
2030 #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;}
2032 LOAD_FUNCPTR(FT_Vector_Unit
)
2033 LOAD_FUNCPTR(FT_Done_Face
)
2034 LOAD_FUNCPTR(FT_Get_Char_Index
)
2035 LOAD_FUNCPTR(FT_Get_Module
)
2036 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2037 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2038 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2039 LOAD_FUNCPTR(FT_Init_FreeType
)
2040 LOAD_FUNCPTR(FT_Load_Glyph
)
2041 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2042 LOAD_FUNCPTR(FT_MulFix
)
2043 LOAD_FUNCPTR(FT_New_Face
)
2044 LOAD_FUNCPTR(FT_New_Memory_Face
)
2045 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2046 LOAD_FUNCPTR(FT_Outline_Transform
)
2047 LOAD_FUNCPTR(FT_Outline_Translate
)
2048 LOAD_FUNCPTR(FT_Select_Charmap
)
2049 LOAD_FUNCPTR(FT_Set_Charmap
)
2050 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2051 LOAD_FUNCPTR(FT_Vector_Transform
)
2054 /* Don't warn if this one is missing */
2055 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2056 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2057 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2058 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2059 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2060 #ifdef HAVE_FREETYPE_FTWINFNT_H
2061 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2063 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2064 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2065 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2066 <= 2.0.3 has FT_Sqrt64 */
2070 if(pFT_Init_FreeType(&library
) != 0) {
2071 ERR("Can't init FreeType library\n");
2072 wine_dlclose(ft_handle
, NULL
, 0);
2076 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
2077 if (pFT_Library_Version
)
2079 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2081 if (FT_Version
.major
<=0)
2087 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2088 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2089 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2090 ((FT_Version
.patch
) & 0x0000ff);
2092 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2093 ERR("Failed to create font mutex\n");
2096 WaitForSingleObject(font_mutex
, INFINITE
);
2098 /* load the system bitmap fonts */
2099 load_system_fonts();
2101 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2102 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2103 strcatW(windowsdir
, fontsW
);
2104 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2106 ReadFontDir(unixname
, FALSE
);
2107 HeapFree(GetProcessHeap(), 0, unixname
);
2110 /* load the system truetype fonts */
2111 data_dir
= wine_get_data_dir();
2112 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2113 strcpy(unixname
, data_dir
);
2114 strcat(unixname
, "/fonts/");
2115 ReadFontDir(unixname
, TRUE
);
2116 HeapFree(GetProcessHeap(), 0, unixname
);
2119 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2120 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2121 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2123 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2124 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2125 &hkey
) == ERROR_SUCCESS
) {
2127 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2128 &valuelen
, &datalen
, NULL
, NULL
);
2130 valuelen
++; /* returned value doesn't include room for '\0' */
2131 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2132 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2135 dlen
= datalen
* sizeof(WCHAR
);
2137 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2138 &dlen
) == ERROR_SUCCESS
) {
2139 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2141 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2143 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2144 HeapFree(GetProcessHeap(), 0, unixname
);
2147 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2149 WCHAR pathW
[MAX_PATH
];
2150 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2153 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2154 if((unixname
= wine_get_unix_file_name(pathW
)))
2156 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2157 HeapFree(GetProcessHeap(), 0, unixname
);
2160 load_font_from_data_dir(data
);
2162 /* reset dlen and vlen */
2167 HeapFree(GetProcessHeap(), 0, data
);
2168 HeapFree(GetProcessHeap(), 0, valueW
);
2172 load_fontconfig_fonts();
2174 /* then look in any directories that we've specified in the config file */
2175 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2176 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2182 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2184 len
+= sizeof(WCHAR
);
2185 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2186 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2188 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2189 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2190 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2191 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2195 LPSTR next
= strchr( ptr
, ':' );
2196 if (next
) *next
++ = 0;
2197 ReadFontDir( ptr
, TRUE
);
2200 HeapFree( GetProcessHeap(), 0, valueA
);
2202 HeapFree( GetProcessHeap(), 0, valueW
);
2211 update_reg_entries();
2213 init_system_links();
2215 ReleaseMutex(font_mutex
);
2219 "Wine cannot find certain functions that it needs inside the FreeType\n"
2220 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2221 "FreeType to at least version 2.0.5.\n"
2222 "http://www.freetype.org\n");
2223 wine_dlclose(ft_handle
, NULL
, 0);
2229 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2232 TT_HoriHeader
*pHori
;
2236 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2237 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2239 if(height
== 0) height
= 16;
2241 /* Calc. height of EM square:
2243 * For +ve lfHeight we have
2244 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2245 * Re-arranging gives:
2246 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2248 * For -ve lfHeight we have
2250 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2251 * with il = winAscent + winDescent - units_per_em]
2256 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2257 ppem
= ft_face
->units_per_EM
* height
/
2258 (pHori
->Ascender
- pHori
->Descender
);
2260 ppem
= ft_face
->units_per_EM
* height
/
2261 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2269 static struct font_mapping
*map_font_file( const char *name
)
2271 struct font_mapping
*mapping
;
2275 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2276 if (fstat( fd
, &st
) == -1) goto error
;
2278 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2280 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2282 mapping
->refcount
++;
2287 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2290 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2293 if (mapping
->data
== MAP_FAILED
)
2295 HeapFree( GetProcessHeap(), 0, mapping
);
2298 mapping
->refcount
= 1;
2299 mapping
->dev
= st
.st_dev
;
2300 mapping
->ino
= st
.st_ino
;
2301 mapping
->size
= st
.st_size
;
2302 list_add_tail( &mappings_list
, &mapping
->entry
);
2310 static void unmap_font_file( struct font_mapping
*mapping
)
2312 if (!--mapping
->refcount
)
2314 list_remove( &mapping
->entry
);
2315 munmap( mapping
->data
, mapping
->size
);
2316 HeapFree( GetProcessHeap(), 0, mapping
);
2320 static LONG
load_VDMX(GdiFont
*, LONG
);
2322 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2329 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2333 if (!(font
->mapping
= map_font_file( face
->file
)))
2335 WARN("failed to map %s\n", debugstr_a(face
->file
));
2338 data_ptr
= font
->mapping
->data
;
2339 data_size
= font
->mapping
->size
;
2343 data_ptr
= face
->font_data_ptr
;
2344 data_size
= face
->font_data_size
;
2347 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2349 ERR("FT_New_Face rets %d\n", err
);
2353 /* set it here, as load_VDMX needs it */
2354 font
->ft_face
= ft_face
;
2356 if(FT_IS_SCALABLE(ft_face
)) {
2357 /* load the VDMX table if we have one */
2358 font
->ppem
= load_VDMX(font
, height
);
2360 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2362 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2363 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2365 font
->ppem
= height
;
2366 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2367 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2373 static int get_nearest_charset(Face
*face
, int *cp
)
2375 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2376 a single face with the requested charset. The idea is to check if
2377 the selected font supports the current ANSI codepage, if it does
2378 return the corresponding charset, else return the first charset */
2381 int acp
= GetACP(), i
;
2385 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2386 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2387 return csi
.ciCharset
;
2389 for(i
= 0; i
< 32; i
++) {
2391 if(face
->fs
.fsCsb
[0] & fs0
) {
2392 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2394 return csi
.ciCharset
;
2397 FIXME("TCI failing on %x\n", fs0
);
2401 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2402 face
->fs
.fsCsb
[0], face
->file
);
2404 return DEFAULT_CHARSET
;
2407 static GdiFont
*alloc_font(void)
2409 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2411 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2412 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2414 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2415 ret
->total_kern_pairs
= (DWORD
)-1;
2416 ret
->kern_pairs
= NULL
;
2417 list_init(&ret
->hfontlist
);
2418 list_init(&ret
->child_fonts
);
2422 static void free_font(GdiFont
*font
)
2424 struct list
*cursor
, *cursor2
;
2427 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2429 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2430 struct list
*first_hfont
;
2431 HFONTLIST
*hfontlist
;
2432 list_remove(cursor
);
2435 first_hfont
= list_head(&child
->font
->hfontlist
);
2436 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2437 DeleteObject(hfontlist
->hfont
);
2438 HeapFree(GetProcessHeap(), 0, hfontlist
);
2439 free_font(child
->font
);
2441 HeapFree(GetProcessHeap(), 0, child
);
2444 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2445 if (font
->mapping
) unmap_font_file( font
->mapping
);
2446 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2447 HeapFree(GetProcessHeap(), 0, font
->potm
);
2448 HeapFree(GetProcessHeap(), 0, font
->name
);
2449 for (i
= 0; i
< font
->gmsize
; i
++)
2450 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2451 HeapFree(GetProcessHeap(), 0, font
->gm
);
2452 HeapFree(GetProcessHeap(), 0, font
);
2456 /*************************************************************
2459 * load the vdmx entry for the specified height
2462 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2463 ( ( (FT_ULong)_x4 << 24 ) | \
2464 ( (FT_ULong)_x3 << 16 ) | \
2465 ( (FT_ULong)_x2 << 8 ) | \
2468 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2483 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2487 BYTE devXRatio
, devYRatio
;
2488 USHORT numRecs
, numRatios
;
2489 DWORD result
, offset
= -1;
2493 /* For documentation on VDMX records, see
2494 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2497 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2499 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2502 /* FIXME: need the real device aspect ratio */
2506 numRecs
= GET_BE_WORD(hdr
[1]);
2507 numRatios
= GET_BE_WORD(hdr
[2]);
2509 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2510 for(i
= 0; i
< numRatios
; i
++) {
2513 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2514 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2517 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2519 if((ratio
.xRatio
== 0 &&
2520 ratio
.yStartRatio
== 0 &&
2521 ratio
.yEndRatio
== 0) ||
2522 (devXRatio
== ratio
.xRatio
&&
2523 devYRatio
>= ratio
.yStartRatio
&&
2524 devYRatio
<= ratio
.yEndRatio
))
2526 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2527 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2528 offset
= GET_BE_WORD(tmp
);
2534 FIXME("No suitable ratio found\n");
2538 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2540 BYTE startsz
, endsz
;
2543 recs
= GET_BE_WORD(group
.recs
);
2544 startsz
= group
.startsz
;
2545 endsz
= group
.endsz
;
2547 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2549 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2550 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2551 if(result
== GDI_ERROR
) {
2552 FIXME("Failed to retrieve vTable\n");
2557 for(i
= 0; i
< recs
; i
++) {
2558 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2559 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2560 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2562 if(yMax
+ -yMin
== height
) {
2565 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2568 if(yMax
+ -yMin
> height
) {
2571 goto end
; /* failed */
2573 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2574 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2575 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2576 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2582 TRACE("ppem not found for height %d\n", height
);
2586 if(ppem
< startsz
|| ppem
> endsz
)
2589 for(i
= 0; i
< recs
; i
++) {
2591 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2593 if(yPelHeight
> ppem
)
2596 if(yPelHeight
== ppem
) {
2597 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2598 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2599 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2605 HeapFree(GetProcessHeap(), 0, vTable
);
2611 static BOOL
fontcmp(GdiFont
*font
, FONT_DESC
*fd
)
2613 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2614 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2615 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2616 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2617 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2620 static void calc_hash(FONT_DESC
*pfd
)
2622 DWORD hash
= 0, *ptr
, two_chars
;
2626 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2628 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2630 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2632 pwc
= (WCHAR
*)&two_chars
;
2634 *pwc
= toupperW(*pwc
);
2636 *pwc
= toupperW(*pwc
);
2640 hash
^= !pfd
->can_use_bitmap
;
2645 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2650 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2652 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
2653 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2654 fd
.can_use_bitmap
= can_use_bitmap
;
2657 /* try the in-use list */
2658 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2659 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2660 if(!fontcmp(ret
, &fd
)) {
2661 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2662 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2663 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2664 if(hflist
->hfont
== hfont
)
2667 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2668 hflist
->hfont
= hfont
;
2669 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2674 /* then the unused list */
2675 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2676 while(font_elem_ptr
) {
2677 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2678 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2679 if(!fontcmp(ret
, &fd
)) {
2680 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2681 assert(list_empty(&ret
->hfontlist
));
2682 TRACE("Found %p in unused list\n", ret
);
2683 list_remove(&ret
->entry
);
2684 list_add_head(&gdi_font_list
, &ret
->entry
);
2685 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2686 hflist
->hfont
= hfont
;
2687 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2695 /*************************************************************
2696 * create_child_font_list
2698 static BOOL
create_child_font_list(GdiFont
*font
)
2701 SYSTEM_LINKS
*font_link
;
2702 CHILD_FONT
*font_link_entry
, *new_child
;
2704 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2706 if(!strcmpW(font_link
->font_name
, font
->name
))
2708 TRACE("found entry in system list\n");
2709 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2711 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2712 new_child
->face
= font_link_entry
->face
;
2713 new_child
->font
= NULL
;
2714 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2715 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
2725 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2727 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2729 if (pFT_Set_Charmap
)
2732 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2734 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2736 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2738 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2740 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2741 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2743 switch (ft_face
->charmaps
[i
]->platform_id
)
2746 cmap_def
= ft_face
->charmaps
[i
];
2748 case 0: /* Apple Unicode */
2749 cmap0
= ft_face
->charmaps
[i
];
2751 case 1: /* Macintosh */
2752 cmap1
= ft_face
->charmaps
[i
];
2755 cmap2
= ft_face
->charmaps
[i
];
2757 case 3: /* Microsoft */
2758 cmap3
= ft_face
->charmaps
[i
];
2763 if (cmap3
) /* prefer Microsoft cmap table */
2764 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2766 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2768 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2770 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2772 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2774 return ft_err
== FT_Err_Ok
;
2777 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
2780 /*************************************************************
2781 * WineEngCreateFontInstance
2784 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2787 Face
*face
, *best
, *best_bitmap
;
2788 Family
*family
, *last_resort_family
;
2789 struct list
*family_elem_ptr
, *face_elem_ptr
;
2790 INT height
, width
= 0;
2791 unsigned int score
= 0, new_score
;
2792 signed int diff
= 0, newdiff
;
2793 BOOL bd
, it
, can_use_bitmap
;
2798 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2800 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2801 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2802 if(hflist
->hfont
== hfont
)
2806 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
2807 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2809 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2810 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2811 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2814 /* check the cache first */
2815 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2816 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2820 TRACE("not in cache\n");
2821 if(list_empty(&font_list
)) /* No fonts installed */
2823 TRACE("No fonts installed\n");
2826 if(!have_installed_roman_font
)
2828 TRACE("No roman font installed\n");
2834 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
2835 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
2836 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
2837 calc_hash(&ret
->font_desc
);
2838 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2839 hflist
->hfont
= hfont
;
2840 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2843 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2844 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2845 original value lfCharSet. Note this is a special case for
2846 Symbol and doesn't happen at least for "Wingdings*" */
2848 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
2849 lf
.lfCharSet
= SYMBOL_CHARSET
;
2851 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
2852 switch(lf
.lfCharSet
) {
2853 case DEFAULT_CHARSET
:
2854 csi
.fs
.fsCsb
[0] = 0;
2857 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
2858 csi
.fs
.fsCsb
[0] = 0;
2864 if(lf
.lfFaceName
[0] != '\0') {
2866 SYSTEM_LINKS
*font_link
;
2867 CHILD_FONT
*font_link_entry
;
2869 psub
= get_font_subst(&font_subst_list
, lf
.lfFaceName
, lf
.lfCharSet
);
2872 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
2873 debugstr_w(psub
->to
.name
));
2874 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2877 /* We want a match on name and charset or just name if
2878 charset was DEFAULT_CHARSET. If the latter then
2879 we fixup the returned charset later in get_nearest_charset
2880 where we'll either use the charset of the current ansi codepage
2881 or if that's unavailable the first charset that the font supports.
2883 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2884 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2885 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2886 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2887 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2888 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2889 if(face
->scalable
|| can_use_bitmap
)
2896 * Try check the SystemLink list first for a replacement font.
2897 * We may find good replacements there.
2899 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2901 if(!strcmpiW(font_link
->font_name
, lf
.lfFaceName
))
2903 TRACE("found entry in system list\n");
2904 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2906 face
= font_link_entry
->face
;
2907 family
= face
->family
;
2908 if(csi
.fs
.fsCsb
[0] &
2909 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
2911 if(face
->scalable
|| can_use_bitmap
)
2919 /* If requested charset was DEFAULT_CHARSET then try using charset
2920 corresponding to the current ansi codepage */
2921 if(!csi
.fs
.fsCsb
[0]) {
2923 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
2924 FIXME("TCI failed on codepage %d\n", acp
);
2925 csi
.fs
.fsCsb
[0] = 0;
2927 lf
.lfCharSet
= csi
.ciCharset
;
2930 /* Face families are in the top 4 bits of lfPitchAndFamily,
2931 so mask with 0xF0 before testing */
2933 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
2934 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
2935 strcpyW(lf
.lfFaceName
, defFixed
);
2936 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
2937 strcpyW(lf
.lfFaceName
, defSerif
);
2938 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
2939 strcpyW(lf
.lfFaceName
, defSans
);
2941 strcpyW(lf
.lfFaceName
, defSans
);
2942 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2943 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2944 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2945 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2946 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2947 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2948 if(face
->scalable
|| can_use_bitmap
)
2954 last_resort_family
= NULL
;
2955 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2956 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2957 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2958 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2959 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
2962 if(can_use_bitmap
&& !last_resort_family
)
2963 last_resort_family
= family
;
2968 if(last_resort_family
) {
2969 family
= last_resort_family
;
2970 csi
.fs
.fsCsb
[0] = 0;
2974 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2975 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2976 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2977 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2978 if(face
->scalable
) {
2979 csi
.fs
.fsCsb
[0] = 0;
2980 WARN("just using first face for now\n");
2983 if(can_use_bitmap
&& !last_resort_family
)
2984 last_resort_family
= family
;
2987 if(!last_resort_family
) {
2988 FIXME("can't find a single appropriate font - bailing\n");
2993 WARN("could only find a bitmap font - this will probably look awful!\n");
2994 family
= last_resort_family
;
2995 csi
.fs
.fsCsb
[0] = 0;
2998 it
= lf
.lfItalic
? 1 : 0;
2999 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3001 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
3002 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
3004 face
= best
= best_bitmap
= NULL
;
3005 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3007 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3009 new_score
= (face
->Italic
^ it
) + (face
->Bold
^ bd
);
3010 if(!best
|| new_score
<= score
)
3012 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3013 face
->Italic
, face
->Bold
, it
, bd
);
3016 if(best
->scalable
&& score
== 0) break;
3020 newdiff
= height
- (signed int)(best
->size
.height
);
3022 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3023 if(!best_bitmap
|| new_score
< score
||
3024 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3026 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3029 if(score
== 0 && diff
== 0) break;
3036 face
= best
->scalable
? best
: best_bitmap
;
3037 ret
->fake_italic
= (it
&& !face
->Italic
);
3038 ret
->fake_bold
= (bd
&& !face
->Bold
);
3040 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
3042 if(csi
.fs
.fsCsb
[0]) {
3043 ret
->charset
= lf
.lfCharSet
;
3044 ret
->codepage
= csi
.ciACP
;
3047 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3049 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3050 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3052 if(!face
->scalable
) {
3053 width
= face
->size
.x_ppem
>> 6;
3054 height
= face
->size
.y_ppem
>> 6;
3056 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3064 ret
->ntmFlags
= face
->ntmFlags
;
3066 if (ret
->charset
== SYMBOL_CHARSET
&&
3067 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3070 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3074 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3077 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3078 ret
->name
= strdupW(family
->FamilyName
);
3079 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3080 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3081 create_child_font_list(ret
);
3083 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3085 ret
->aveWidth
= FT_IS_SCALABLE(ret
->ft_face
) ? abs(lf
.lfWidth
) : 0;
3086 list_add_head(&gdi_font_list
, &ret
->entry
);
3090 static void dump_gdi_font_list(void)
3093 struct list
*elem_ptr
;
3095 TRACE("---------- gdiFont Cache ----------\n");
3096 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3097 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3098 TRACE("gdiFont=%p %s %d\n",
3099 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3102 TRACE("---------- Unused gdiFont Cache ----------\n");
3103 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3104 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3105 TRACE("gdiFont=%p %s %d\n",
3106 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3110 /*************************************************************
3111 * WineEngDestroyFontInstance
3113 * free the gdiFont associated with this handle
3116 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3121 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3124 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3126 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3127 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3128 if(hflist
->hfont
== handle
)
3130 TRACE("removing child font %p from child list\n", gdiFont
);
3131 list_remove(&gdiFont
->entry
);
3136 TRACE("destroying hfont=%p\n", handle
);
3138 dump_gdi_font_list();
3140 font_elem_ptr
= list_head(&gdi_font_list
);
3141 while(font_elem_ptr
) {
3142 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3143 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3145 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3146 while(hfontlist_elem_ptr
) {
3147 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3148 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3149 if(hflist
->hfont
== handle
) {
3150 list_remove(&hflist
->entry
);
3151 HeapFree(GetProcessHeap(), 0, hflist
);
3155 if(list_empty(&gdiFont
->hfontlist
)) {
3156 TRACE("Moving to Unused list\n");
3157 list_remove(&gdiFont
->entry
);
3158 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3163 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3164 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3165 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3166 while(font_elem_ptr
) {
3167 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3168 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3169 TRACE("freeing %p\n", gdiFont
);
3170 list_remove(&gdiFont
->entry
);
3176 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3177 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3179 OUTLINETEXTMETRICW
*potm
= NULL
;
3181 TEXTMETRICW tm
, *ptm
;
3182 GdiFont
*font
= alloc_font();
3185 if(face
->scalable
) {
3189 height
= face
->size
.y_ppem
>> 6;
3190 width
= face
->size
.x_ppem
>> 6;
3193 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3199 font
->name
= strdupW(face
->family
->FamilyName
);
3200 font
->ntmFlags
= face
->ntmFlags
;
3202 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
3204 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
3206 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3207 WineEngGetOutlineTextMetrics(font
, size
, potm
);
3208 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
3210 WineEngGetTextMetrics(font
, &tm
);
3214 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
3215 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
3216 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
3217 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
3218 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
3219 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
3220 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
3221 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
3222 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
3223 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
3224 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
3225 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
3226 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
3227 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
3228 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
3229 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
3230 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
3231 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
3232 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
3233 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
3234 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
3235 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3236 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3237 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3240 if (ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
)
3241 *ptype
|= TRUETYPE_FONTTYPE
;
3242 if (ptm
->tmPitchAndFamily
& TMPF_DEVICE
)
3243 *ptype
|= DEVICE_FONTTYPE
;
3244 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
3245 *ptype
|= RASTER_FONTTYPE
;
3247 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
3248 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
3249 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
3250 pntm
->ntmTm
.ntmFlags
|= face
->ntmFlags
;
3252 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3253 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3254 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
3257 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
3259 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3260 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
3262 lstrcpynW(pelf
->elfFullName
,
3263 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
3265 lstrcpynW(pelf
->elfStyle
,
3266 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
3269 HeapFree(GetProcessHeap(), 0, potm
);
3271 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3273 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3274 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
3275 pelf
->elfStyle
[0] = '\0';
3278 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3283 /*************************************************************
3287 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3291 struct list
*family_elem_ptr
, *face_elem_ptr
;
3293 NEWTEXTMETRICEXW ntm
;
3294 DWORD type
, ret
= 1;
3300 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3302 if(plf
->lfFaceName
[0]) {
3304 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3307 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3308 debugstr_w(psub
->to
.name
));
3309 memcpy(&lf
, plf
, sizeof(lf
));
3310 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3314 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3315 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3316 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3317 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3318 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3319 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3320 for(i
= 0; i
< 32; i
++) {
3321 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3322 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3323 strcpyW(elf
.elfScript
, OEM_DOSW
);
3324 i
= 32; /* break out of loop */
3325 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3328 fs
.fsCsb
[0] = 1L << i
;
3330 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3332 csi
.ciCharset
= DEFAULT_CHARSET
;
3333 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3334 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3335 elf
.elfLogFont
.lfCharSet
=
3336 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3338 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3340 FIXME("Unknown elfscript for bit %d\n", i
);
3343 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3344 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3345 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3346 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3347 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3348 ntm
.ntmTm
.ntmFlags
);
3349 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3356 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3357 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3358 face_elem_ptr
= list_head(&family
->faces
);
3359 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3360 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3361 for(i
= 0; i
< 32; i
++) {
3362 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3363 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3364 strcpyW(elf
.elfScript
, OEM_DOSW
);
3365 i
= 32; /* break out of loop */
3366 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3369 fs
.fsCsb
[0] = 1L << i
;
3371 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3373 csi
.ciCharset
= DEFAULT_CHARSET
;
3374 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3375 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3376 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3379 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3381 FIXME("Unknown elfscript for bit %d\n", i
);
3384 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3385 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3386 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3387 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3388 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3389 ntm
.ntmTm
.ntmFlags
);
3390 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3399 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3401 pt
->x
.value
= vec
->x
>> 6;
3402 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3403 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3404 pt
->y
.value
= vec
->y
>> 6;
3405 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3406 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3410 /***************************************************
3411 * According to the MSDN documentation on WideCharToMultiByte,
3412 * certain codepages cannot set the default_used parameter.
3413 * This returns TRUE if the codepage can set that parameter, false else
3414 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3416 static BOOL
codepage_sets_default_used(UINT codepage
)
3429 static FT_UInt
get_glyph_index(GdiFont
*font
, UINT glyph
)
3431 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
3432 WCHAR wc
= (WCHAR
)glyph
;
3434 BOOL
*default_used_pointer
;
3437 default_used_pointer
= NULL
;
3438 default_used
= FALSE
;
3439 if (codepage_sets_default_used(font
->codepage
))
3440 default_used_pointer
= &default_used
;
3441 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
3444 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
3445 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
3449 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
3450 glyph
= glyph
+ 0xf000;
3451 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
3454 /*************************************************************
3455 * WineEngGetGlyphIndices
3457 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3459 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
3460 LPWORD pgi
, DWORD flags
)
3463 WCHAR default_char
= 0;
3466 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0x001f; /* Indicate non existence */
3468 for(i
= 0; i
< count
; i
++)
3470 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
3475 WineEngGetTextMetrics(font
, &textm
);
3476 default_char
= textm
.tmDefaultChar
;
3478 pgi
[i
] = default_char
;
3484 /*************************************************************
3485 * WineEngGetGlyphOutline
3487 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3488 * except that the first parameter is the HWINEENGFONT of the font in
3489 * question rather than an HDC.
3492 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
3493 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3496 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
3497 FT_Face ft_face
= incoming_font
->ft_face
;
3498 GdiFont
*font
= incoming_font
;
3499 FT_UInt glyph_index
;
3500 DWORD width
, height
, pitch
, needed
= 0;
3501 FT_Bitmap ft_bitmap
;
3503 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
3505 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3506 float widthRatio
= 1.0;
3507 FT_Matrix transMat
= identityMat
;
3508 BOOL needsTransform
= FALSE
;
3511 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
3512 buflen
, buf
, lpmat
);
3514 if(format
& GGO_GLYPH_INDEX
) {
3515 glyph_index
= glyph
;
3516 format
&= ~GGO_GLYPH_INDEX
;
3518 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
3519 ft_face
= font
->ft_face
;
3522 if(glyph_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
3523 font
->gmsize
= (glyph_index
/ GM_BLOCK_SIZE
+ 1);
3524 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
3525 font
->gmsize
* sizeof(GM
*));
3527 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] != NULL
&& FONT_GM(font
,glyph_index
)->init
) {
3528 *lpgm
= FONT_GM(font
,glyph_index
)->gm
;
3529 return 1; /* FIXME */
3533 if (!font
->gm
[glyph_index
/ GM_BLOCK_SIZE
])
3534 font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3536 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) || font
->aveWidth
|| lpmat
)
3537 load_flags
|= FT_LOAD_NO_BITMAP
;
3539 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
3542 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
3546 /* Scaling factor */
3547 if (font
->aveWidth
&& font
->potm
) {
3548 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
3551 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
3552 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
3554 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
3556 bbx
= (right
- left
) >> 6;
3558 /* Scaling transform */
3559 if(font
->aveWidth
) {
3561 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
3564 scaleMat
.yy
= (1 << 16);
3566 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
3567 needsTransform
= TRUE
;
3570 /* Slant transform */
3571 if (font
->fake_italic
) {
3574 slantMat
.xx
= (1 << 16);
3575 slantMat
.xy
= ((1 << 16) >> 2);
3577 slantMat
.yy
= (1 << 16);
3578 pFT_Matrix_Multiply(&slantMat
, &transMat
);
3579 needsTransform
= TRUE
;
3582 /* Rotation transform */
3583 if(font
->orientation
) {
3584 FT_Matrix rotationMat
;
3586 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
3587 pFT_Vector_Unit(&vecAngle
, angle
);
3588 rotationMat
.xx
= vecAngle
.x
;
3589 rotationMat
.xy
= -vecAngle
.y
;
3590 rotationMat
.yx
= -rotationMat
.xy
;
3591 rotationMat
.yy
= rotationMat
.xx
;
3593 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
3594 needsTransform
= TRUE
;
3597 /* Extra transformation specified by caller */
3600 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
3601 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
3602 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
3603 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
3604 pFT_Matrix_Multiply(&extraMat
, &transMat
);
3605 needsTransform
= TRUE
;
3608 if(!needsTransform
) {
3609 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
3610 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
3611 ft_face
->glyph
->metrics
.height
) & -64;
3612 lpgm
->gmCellIncX
= adv
;
3613 lpgm
->gmCellIncY
= 0;
3617 for(xc
= 0; xc
< 2; xc
++) {
3618 for(yc
= 0; yc
< 2; yc
++) {
3619 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
3620 xc
* ft_face
->glyph
->metrics
.width
);
3621 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
3622 yc
* ft_face
->glyph
->metrics
.height
;
3623 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
3624 pFT_Vector_Transform(&vec
, &transMat
);
3625 if(xc
== 0 && yc
== 0) {
3626 left
= right
= vec
.x
;
3627 top
= bottom
= vec
.y
;
3629 if(vec
.x
< left
) left
= vec
.x
;
3630 else if(vec
.x
> right
) right
= vec
.x
;
3631 if(vec
.y
< bottom
) bottom
= vec
.y
;
3632 else if(vec
.y
> top
) top
= vec
.y
;
3637 right
= (right
+ 63) & -64;
3638 bottom
= bottom
& -64;
3639 top
= (top
+ 63) & -64;
3641 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
3642 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
3644 pFT_Vector_Transform(&vec
, &transMat
);
3645 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
3646 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
3648 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
3649 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
3650 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
3651 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
3653 if(format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
)
3655 FONT_GM(font
,glyph_index
)->gm
= *lpgm
;
3656 FONT_GM(font
,glyph_index
)->adv
= adv
;
3657 FONT_GM(font
,glyph_index
)->lsb
= lsb
;
3658 FONT_GM(font
,glyph_index
)->bbx
= bbx
;
3659 FONT_GM(font
,glyph_index
)->init
= TRUE
;
3662 if(format
== GGO_METRICS
)
3663 return 1; /* FIXME */
3665 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) {
3666 TRACE("loaded a bitmap\n");
3672 width
= lpgm
->gmBlackBoxX
;
3673 height
= lpgm
->gmBlackBoxY
;
3674 pitch
= ((width
+ 31) >> 5) << 2;
3675 needed
= pitch
* height
;
3677 if(!buf
|| !buflen
) break;
3679 switch(ft_face
->glyph
->format
) {
3680 case ft_glyph_format_bitmap
:
3682 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3683 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
3684 INT h
= ft_face
->glyph
->bitmap
.rows
;
3686 memcpy(dst
, src
, w
);
3687 src
+= ft_face
->glyph
->bitmap
.pitch
;
3693 case ft_glyph_format_outline
:
3694 ft_bitmap
.width
= width
;
3695 ft_bitmap
.rows
= height
;
3696 ft_bitmap
.pitch
= pitch
;
3697 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
3698 ft_bitmap
.buffer
= buf
;
3700 if(needsTransform
) {
3701 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3704 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3706 /* Note: FreeType will only set 'black' bits for us. */
3707 memset(buf
, 0, needed
);
3708 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3712 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3717 case GGO_GRAY2_BITMAP
:
3718 case GGO_GRAY4_BITMAP
:
3719 case GGO_GRAY8_BITMAP
:
3720 case WINE_GGO_GRAY16_BITMAP
:
3722 unsigned int mult
, row
, col
;
3725 width
= lpgm
->gmBlackBoxX
;
3726 height
= lpgm
->gmBlackBoxY
;
3727 pitch
= (width
+ 3) / 4 * 4;
3728 needed
= pitch
* height
;
3730 if(!buf
|| !buflen
) break;
3732 switch(ft_face
->glyph
->format
) {
3733 case ft_glyph_format_bitmap
:
3735 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3736 INT h
= ft_face
->glyph
->bitmap
.rows
;
3739 for(x
= 0; x
< pitch
; x
++)
3740 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
3741 src
+= ft_face
->glyph
->bitmap
.pitch
;
3746 case ft_glyph_format_outline
:
3748 ft_bitmap
.width
= width
;
3749 ft_bitmap
.rows
= height
;
3750 ft_bitmap
.pitch
= pitch
;
3751 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
3752 ft_bitmap
.buffer
= buf
;
3755 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3757 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3759 memset(ft_bitmap
.buffer
, 0, buflen
);
3761 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3763 if(format
== GGO_GRAY2_BITMAP
)
3765 else if(format
== GGO_GRAY4_BITMAP
)
3767 else if(format
== GGO_GRAY8_BITMAP
)
3769 else if(format
== WINE_GGO_GRAY16_BITMAP
)
3777 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3782 for(row
= 0; row
< height
; row
++) {
3784 for(col
= 0; col
< width
; col
++, ptr
++) {
3785 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
3794 int contour
, point
= 0, first_pt
;
3795 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3796 TTPOLYGONHEADER
*pph
;
3798 DWORD pph_start
, cpfx
, type
;
3800 if(buflen
== 0) buf
= NULL
;
3802 if (needsTransform
&& buf
) {
3803 pFT_Outline_Transform(outline
, &transMat
);
3806 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3808 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3811 pph
->dwType
= TT_POLYGON_TYPE
;
3812 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3814 needed
+= sizeof(*pph
);
3816 while(point
<= outline
->contours
[contour
]) {
3817 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3818 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3819 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3823 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3826 } while(point
<= outline
->contours
[contour
] &&
3827 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3828 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3829 /* At the end of a contour Windows adds the start point, but
3831 if(point
> outline
->contours
[contour
] &&
3832 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3834 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3836 } else if(point
<= outline
->contours
[contour
] &&
3837 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3838 /* add closing pt for bezier */
3840 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3848 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3851 pph
->cb
= needed
- pph_start
;
3857 /* Convert the quadratic Beziers to cubic Beziers.
3858 The parametric eqn for a cubic Bezier is, from PLRM:
3859 r(t) = at^3 + bt^2 + ct + r0
3860 with the control points:
3865 A quadratic Beizer has the form:
3866 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3868 So equating powers of t leads to:
3869 r1 = 2/3 p1 + 1/3 p0
3870 r2 = 2/3 p1 + 1/3 p2
3871 and of course r0 = p0, r3 = p2
3874 int contour
, point
= 0, first_pt
;
3875 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3876 TTPOLYGONHEADER
*pph
;
3878 DWORD pph_start
, cpfx
, type
;
3879 FT_Vector cubic_control
[4];
3880 if(buflen
== 0) buf
= NULL
;
3882 if (needsTransform
&& buf
) {
3883 pFT_Outline_Transform(outline
, &transMat
);
3886 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3888 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3891 pph
->dwType
= TT_POLYGON_TYPE
;
3892 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3894 needed
+= sizeof(*pph
);
3896 while(point
<= outline
->contours
[contour
]) {
3897 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3898 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3899 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3902 if(type
== TT_PRIM_LINE
) {
3904 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3908 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3911 /* FIXME: Possible optimization in endpoint calculation
3912 if there are two consecutive curves */
3913 cubic_control
[0] = outline
->points
[point
-1];
3914 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3915 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3916 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3917 cubic_control
[0].x
>>= 1;
3918 cubic_control
[0].y
>>= 1;
3920 if(point
+1 > outline
->contours
[contour
])
3921 cubic_control
[3] = outline
->points
[first_pt
];
3923 cubic_control
[3] = outline
->points
[point
+1];
3924 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
3925 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3926 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3927 cubic_control
[3].x
>>= 1;
3928 cubic_control
[3].y
>>= 1;
3931 /* r1 = 1/3 p0 + 2/3 p1
3932 r2 = 1/3 p2 + 2/3 p1 */
3933 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3934 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3935 cubic_control
[2] = cubic_control
[1];
3936 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3937 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3938 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3939 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3941 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3942 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3943 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3948 } while(point
<= outline
->contours
[contour
] &&
3949 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3950 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3951 /* At the end of a contour Windows adds the start point,
3952 but only for Beziers and we've already done that.
3954 if(point
<= outline
->contours
[contour
] &&
3955 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3956 /* This is the closing pt of a bezier, but we've already
3957 added it, so just inc point and carry on */
3964 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3967 pph
->cb
= needed
- pph_start
;
3973 FIXME("Unsupported format %d\n", format
);
3979 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
3981 FT_Face ft_face
= font
->ft_face
;
3982 #ifdef HAVE_FREETYPE_FTWINFNT_H
3983 FT_WinFNT_HeaderRec winfnt_header
;
3985 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
3986 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3987 font
->potm
->otmSize
= size
;
3989 #define TM font->potm->otmTextMetrics
3990 #ifdef HAVE_FREETYPE_FTWINFNT_H
3991 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3993 TM
.tmHeight
= winfnt_header
.pixel_height
;
3994 TM
.tmAscent
= winfnt_header
.ascent
;
3995 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3996 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3997 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3998 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3999 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4000 TM
.tmWeight
= winfnt_header
.weight
;
4002 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4003 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4004 TM
.tmFirstChar
= winfnt_header
.first_char
;
4005 TM
.tmLastChar
= winfnt_header
.last_char
;
4006 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4007 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4008 TM
.tmItalic
= winfnt_header
.italic
;
4009 TM
.tmUnderlined
= font
->underline
;
4010 TM
.tmStruckOut
= font
->strikeout
;
4011 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4012 TM
.tmCharSet
= winfnt_header
.charset
;
4017 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4018 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4019 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4020 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4021 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4022 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4023 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4024 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4026 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4027 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4029 TM
.tmLastChar
= 255;
4030 TM
.tmDefaultChar
= 32;
4031 TM
.tmBreakChar
= 32;
4032 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4033 TM
.tmUnderlined
= font
->underline
;
4034 TM
.tmStruckOut
= font
->strikeout
;
4035 /* NB inverted meaning of TMPF_FIXED_PITCH */
4036 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4037 TM
.tmCharSet
= font
->charset
;
4044 /*************************************************************
4045 * WineEngGetTextMetrics
4048 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4051 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4052 if(!get_bitmap_text_metrics(font
))
4055 if(!font
->potm
) return FALSE
;
4056 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
4058 if (font
->aveWidth
) {
4059 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4065 /*************************************************************
4066 * WineEngGetOutlineTextMetrics
4069 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4070 OUTLINETEXTMETRICW
*potm
)
4072 FT_Face ft_face
= font
->ft_face
;
4073 UINT needed
, lenfam
, lensty
, ret
;
4075 TT_HoriHeader
*pHori
;
4076 TT_Postscript
*pPost
;
4077 FT_Fixed x_scale
, y_scale
;
4078 WCHAR
*family_nameW
, *style_nameW
;
4079 static const WCHAR spaceW
[] = {' ', '\0'};
4081 INT ascent
, descent
;
4083 TRACE("font=%p\n", font
);
4085 if(!FT_IS_SCALABLE(ft_face
))
4089 if(cbSize
>= font
->potm
->otmSize
)
4090 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4091 return font
->potm
->otmSize
;
4095 needed
= sizeof(*potm
);
4097 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
4098 family_nameW
= strdupW(font
->name
);
4100 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
4102 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
4103 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
4104 style_nameW
, lensty
/sizeof(WCHAR
));
4106 /* These names should be read from the TT name table */
4108 /* length of otmpFamilyName */
4111 /* length of otmpFaceName */
4112 if(!strcasecmp(ft_face
->style_name
, "regular")) {
4113 needed
+= lenfam
; /* just the family name */
4115 needed
+= lenfam
+ lensty
; /* family + " " + style */
4118 /* length of otmpStyleName */
4121 /* length of otmpFullName */
4122 needed
+= lenfam
+ lensty
;
4125 x_scale
= ft_face
->size
->metrics
.x_scale
;
4126 y_scale
= ft_face
->size
->metrics
.y_scale
;
4128 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4130 FIXME("Can't find OS/2 table - not TT font?\n");
4135 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4137 FIXME("Can't find HHEA table - not TT font?\n");
4142 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
4144 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",
4145 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
4146 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
4147 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
4148 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
4149 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
4151 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
4152 font
->potm
->otmSize
= needed
;
4154 #define TM font->potm->otmTextMetrics
4156 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
4157 ascent
= pHori
->Ascender
;
4158 descent
= -pHori
->Descender
;
4160 ascent
= pOS2
->usWinAscent
;
4161 descent
= pOS2
->usWinDescent
;
4165 TM
.tmAscent
= font
->yMax
;
4166 TM
.tmDescent
= -font
->yMin
;
4167 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4169 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4170 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4171 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4172 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4175 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4178 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4180 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4181 ((ascent
+ descent
) -
4182 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4184 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4185 if (TM
.tmAveCharWidth
== 0) {
4186 TM
.tmAveCharWidth
= 1;
4188 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4189 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4191 TM
.tmDigitizedAspectX
= 300;
4192 TM
.tmDigitizedAspectY
= 300;
4193 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4194 * symbol range to 0 - f0ff
4196 if (font
->charset
== SYMBOL_CHARSET
)
4199 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4200 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4201 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4202 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4203 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4204 TM
.tmUnderlined
= font
->underline
;
4205 TM
.tmStruckOut
= font
->strikeout
;
4207 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4208 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4209 (pOS2
->version
== 0xFFFFU
||
4210 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4211 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4213 TM
.tmPitchAndFamily
= 0;
4215 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4216 case PAN_FAMILY_SCRIPT
:
4217 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4219 case PAN_FAMILY_DECORATIVE
:
4220 case PAN_FAMILY_PICTORIAL
:
4221 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4223 case PAN_FAMILY_TEXT_DISPLAY
:
4224 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4225 TM
.tmPitchAndFamily
= FF_MODERN
;
4227 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4228 case PAN_SERIF_NORMAL_SANS
:
4229 case PAN_SERIF_OBTUSE_SANS
:
4230 case PAN_SERIF_PERP_SANS
:
4231 TM
.tmPitchAndFamily
|= FF_SWISS
;
4234 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4239 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4242 if(FT_IS_SCALABLE(ft_face
))
4243 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4245 if(FT_IS_SFNT(ft_face
))
4247 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
4248 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
4250 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4253 TM
.tmCharSet
= font
->charset
;
4256 font
->potm
->otmFiller
= 0;
4257 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4258 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4259 font
->potm
->otmfsType
= pOS2
->fsType
;
4260 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4261 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4262 font
->potm
->otmItalicAngle
= 0; /* POST table */
4263 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4264 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4265 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4266 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4267 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4268 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
4269 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4270 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
4271 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
4272 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
4273 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
4274 font
->potm
->otmMacDescent
= 0;
4275 font
->potm
->otmMacLineGap
= 0;
4276 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
4277 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
4278 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
4279 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
4280 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
4281 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
4282 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
4283 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
4284 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
4285 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
4286 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
4288 font
->potm
->otmsUnderscoreSize
= 0;
4289 font
->potm
->otmsUnderscorePosition
= 0;
4291 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
4292 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
4295 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4296 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
4297 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
4298 strcpyW((WCHAR
*)cp
, family_nameW
);
4300 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
4301 strcpyW((WCHAR
*)cp
, style_nameW
);
4303 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
4304 strcpyW((WCHAR
*)cp
, family_nameW
);
4305 if(strcasecmp(ft_face
->style_name
, "regular")) {
4306 strcatW((WCHAR
*)cp
, spaceW
);
4307 strcatW((WCHAR
*)cp
, style_nameW
);
4308 cp
+= lenfam
+ lensty
;
4311 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
4312 strcpyW((WCHAR
*)cp
, family_nameW
);
4313 strcatW((WCHAR
*)cp
, spaceW
);
4314 strcatW((WCHAR
*)cp
, style_nameW
);
4317 if(potm
&& needed
<= cbSize
)
4318 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4321 HeapFree(GetProcessHeap(), 0, style_nameW
);
4322 HeapFree(GetProcessHeap(), 0, family_nameW
);
4327 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
4329 HFONTLIST
*hfontlist
;
4330 child
->font
= alloc_font();
4331 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
4332 if(!child
->font
->ft_face
)
4334 free_font(child
->font
);
4339 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
4340 child
->font
->orientation
= font
->orientation
;
4341 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
4342 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
4343 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
4344 child
->font
->base_font
= font
;
4345 list_add_head(&child_font_list
, &child
->font
->entry
);
4346 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
4350 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
4353 CHILD_FONT
*child_font
;
4356 font
= font
->base_font
;
4358 *linked_font
= font
;
4360 if((*glyph
= get_glyph_index(font
, c
)))
4363 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
4365 if(!child_font
->font
)
4366 if(!load_child_font(font
, child_font
))
4369 if(!child_font
->font
->ft_face
)
4371 g
= get_glyph_index(child_font
->font
, c
);
4375 *linked_font
= child_font
->font
;
4382 /*************************************************************
4383 * WineEngGetCharWidth
4386 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4391 FT_UInt glyph_index
;
4392 GdiFont
*linked_font
;
4394 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4396 for(c
= firstChar
; c
<= lastChar
; c
++) {
4397 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4398 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4399 &gm
, 0, NULL
, NULL
);
4400 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
4405 /*************************************************************
4406 * WineEngGetCharABCWidths
4409 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4414 FT_UInt glyph_index
;
4415 GdiFont
*linked_font
;
4417 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4419 if(!FT_IS_SCALABLE(font
->ft_face
))
4422 for(c
= firstChar
; c
<= lastChar
; c
++) {
4423 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4424 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4425 &gm
, 0, NULL
, NULL
);
4426 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
4427 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
4428 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
4429 FONT_GM(linked_font
,glyph_index
)->bbx
;
4434 /*************************************************************
4435 * WineEngGetCharABCWidthsI
4438 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4443 FT_UInt glyph_index
;
4444 GdiFont
*linked_font
;
4446 if(!FT_IS_SCALABLE(font
->ft_face
))
4449 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
4451 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
4452 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4453 &gm
, 0, NULL
, NULL
);
4454 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
4455 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
4456 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
4457 - FONT_GM(linked_font
,c
)->bbx
;
4460 for(c
= 0; c
< count
; c
++) {
4461 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4462 &gm
, 0, NULL
, NULL
);
4463 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
4464 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
4465 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
4466 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
4472 /*************************************************************
4473 * WineEngGetTextExtentExPoint
4476 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4477 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4483 FT_UInt glyph_index
;
4484 GdiFont
*linked_font
;
4486 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
4490 WineEngGetTextMetrics(font
, &tm
);
4491 size
->cy
= tm
.tmHeight
;
4493 for(idx
= 0; idx
< count
; idx
++) {
4494 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
4495 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4496 &gm
, 0, NULL
, NULL
);
4497 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
4499 if (! pnfit
|| ext
<= max_ext
) {
4509 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4513 /*************************************************************
4514 * WineEngGetTextExtentPointI
4517 BOOL
WineEngGetTextExtentPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4524 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
4527 WineEngGetTextMetrics(font
, &tm
);
4528 size
->cy
= tm
.tmHeight
;
4530 for(idx
= 0; idx
< count
; idx
++) {
4531 WineEngGetGlyphOutline(font
, indices
[idx
],
4532 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
4534 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
4536 TRACE("return %d,%d\n", size
->cx
, size
->cy
);
4540 /*************************************************************
4541 * WineEngGetFontData
4544 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4547 FT_Face ft_face
= font
->ft_face
;
4551 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4552 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
4553 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
4555 if(!FT_IS_SFNT(ft_face
))
4563 if(table
) { /* MS tags differ in endidness from FT ones */
4564 table
= table
>> 24 | table
<< 24 |
4565 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
4568 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4569 if(pFT_Load_Sfnt_Table
) {
4570 /* make sure value of len is the value freetype says it needs */
4572 FT_ULong needed
= 0;
4573 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4574 if( !err
&& needed
< len
) len
= needed
;
4576 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4578 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4579 else { /* Do it the hard way */
4580 TT_Face tt_face
= (TT_Face
) ft_face
;
4581 SFNT_Interface
*sfnt
;
4582 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
4585 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
4589 /* A field was added in the middle of the structure in 2.1.x */
4590 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
4592 /* make sure value of len is the value freetype says it needs */
4594 FT_ULong needed
= 0;
4595 err
= sfnt
->load_any(tt_face
, table
, offset
, NULL
, &needed
);
4596 if( !err
&& needed
< len
) len
= needed
;
4598 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
4604 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4605 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4606 "Please upgrade your freetype library.\n");
4609 err
= FT_Err_Unimplemented_Feature
;
4613 TRACE("Can't find table %c%c%c%c\n",
4614 /* bytes were reversed */
4615 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4616 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4622 /*************************************************************
4623 * WineEngGetTextFace
4626 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4629 lstrcpynW(str
, font
->name
, count
);
4630 return strlenW(font
->name
);
4632 return strlenW(font
->name
) + 1;
4635 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4637 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
4638 return font
->charset
;
4641 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4643 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
4644 struct list
*first_hfont
;
4647 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
4648 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
4649 if(font
== linked_font
)
4650 *new_hfont
= dc
->hFont
;
4653 first_hfont
= list_head(&linked_font
->hfontlist
);
4654 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
4660 /* Retrieve a list of supported Unicode ranges for a given font.
4661 * Can be called with NULL gs to calculate the buffer size. Returns
4662 * the number of ranges found.
4664 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
4666 DWORD num_ranges
= 0;
4668 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4671 FT_ULong char_code
, char_code_prev
;
4674 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
4676 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4677 face
->num_glyphs
, glyph_code
, char_code
);
4679 if (!glyph_code
) return 0;
4683 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4684 gs
->ranges
[0].cGlyphs
= 0;
4685 gs
->cGlyphsSupported
= 0;
4691 if (char_code
< char_code_prev
)
4693 ERR("expected increasing char code from FT_Get_Next_Char\n");
4696 if (char_code
- char_code_prev
> 1)
4701 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4702 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4703 gs
->cGlyphsSupported
++;
4708 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4709 gs
->cGlyphsSupported
++;
4711 char_code_prev
= char_code
;
4712 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
4716 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
4721 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
4724 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
4726 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
4729 glyphset
->cbThis
= size
;
4730 glyphset
->cRanges
= num_ranges
;
4735 /*************************************************************
4738 BOOL
WineEngFontIsLinked(GdiFont
*font
)
4740 return !list_empty(&font
->child_fonts
);
4743 static BOOL
is_hinting_enabled(void)
4745 /* Use the >= 2.2.0 function if available */
4746 if(pFT_Get_TrueType_Engine_Type
)
4748 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
4749 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
4751 #ifdef FT_DRIVER_HAS_HINTER
4756 /* otherwise if we've been compiled with < 2.2.0 headers
4757 use the internal macro */
4758 mod
= pFT_Get_Module(library
, "truetype");
4759 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
4767 /*************************************************************************
4768 * GetRasterizerCaps (GDI32.@)
4770 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
4772 static int hinting
= -1;
4776 hinting
= is_hinting_enabled();
4777 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
4780 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
4781 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
4782 lprs
->nLanguageID
= 0;
4786 /*************************************************************************
4787 * Kerning support for TrueType fonts
4789 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4791 struct TT_kern_table
4797 struct TT_kern_subtable
4806 USHORT horizontal
: 1;
4808 USHORT cross_stream
: 1;
4809 USHORT override
: 1;
4810 USHORT reserved1
: 4;
4816 struct TT_format0_kern_subtable
4820 USHORT entrySelector
;
4831 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
4832 const struct TT_format0_kern_subtable
*tt_f0_ks
,
4833 const USHORT
*glyph_to_char
,
4834 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
4837 const struct TT_kern_pair
*tt_kern_pair
;
4839 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
4841 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
4843 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4844 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
4845 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
4847 if (!kern_pair
|| !cPairs
)
4850 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
4852 nPairs
= min(nPairs
, cPairs
);
4854 for (i
= 0; i
< nPairs
; i
++)
4856 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
4857 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
4858 /* this algorithm appears to better match what Windows does */
4859 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
4860 if (kern_pair
->iKernAmount
< 0)
4862 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
4863 kern_pair
->iKernAmount
-= font
->ppem
;
4865 else if (kern_pair
->iKernAmount
> 0)
4867 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
4868 kern_pair
->iKernAmount
+= font
->ppem
;
4870 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
4872 TRACE("left %u right %u value %d\n",
4873 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
4877 TRACE("copied %u entries\n", nPairs
);
4881 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
4885 const struct TT_kern_table
*tt_kern_table
;
4886 const struct TT_kern_subtable
*tt_kern_subtable
;
4888 USHORT
*glyph_to_char
;
4890 if (font
->total_kern_pairs
!= (DWORD
)-1)
4892 if (cPairs
&& kern_pair
)
4894 cPairs
= min(cPairs
, font
->total_kern_pairs
);
4895 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
4898 return font
->total_kern_pairs
;
4901 font
->total_kern_pairs
= 0;
4903 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
4905 if (length
== GDI_ERROR
)
4907 TRACE("no kerning data in the font\n");
4911 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
4914 WARN("Out of memory\n");
4918 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
4920 /* build a glyph index to char code map */
4921 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
4924 WARN("Out of memory allocating a glyph index to char code map\n");
4925 HeapFree(GetProcessHeap(), 0, buf
);
4929 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4935 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
4937 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4938 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
4942 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4944 /* FIXME: This doesn't match what Windows does: it does some fancy
4945 * things with duplicate glyph index to char code mappings, while
4946 * we just avoid overriding existing entries.
4948 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
4949 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
4951 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
4958 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
4959 for (n
= 0; n
<= 65535; n
++)
4960 glyph_to_char
[n
] = (USHORT
)n
;
4963 tt_kern_table
= buf
;
4964 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
4965 TRACE("version %u, nTables %u\n",
4966 GET_BE_WORD(tt_kern_table
->version
), nTables
);
4968 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
4970 for (i
= 0; i
< nTables
; i
++)
4972 struct TT_kern_subtable tt_kern_subtable_copy
;
4974 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
4975 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
4976 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
4978 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4979 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
4980 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
4982 /* According to the TrueType specification this is the only format
4983 * that will be properly interpreted by Windows and OS/2
4985 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
4987 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
4989 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4990 glyph_to_char
, NULL
, 0);
4991 font
->total_kern_pairs
+= new_chunk
;
4993 if (!font
->kern_pairs
)
4994 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
4995 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
4997 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
4998 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5000 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5001 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
5004 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
5006 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
5009 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
5010 HeapFree(GetProcessHeap(), 0, buf
);
5012 if (cPairs
&& kern_pair
)
5014 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5015 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5018 return font
->total_kern_pairs
;
5021 #else /* HAVE_FREETYPE */
5023 /*************************************************************************/
5025 BOOL
WineEngInit(void)
5029 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
5033 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
5038 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5043 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
5044 LPWORD pgi
, DWORD flags
)
5049 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
5050 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5053 ERR("called but we don't have FreeType\n");
5057 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5059 ERR("called but we don't have FreeType\n");
5063 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5064 OUTLINETEXTMETRICW
*potm
)
5066 ERR("called but we don't have FreeType\n");
5070 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5073 ERR("called but we don't have FreeType\n");
5077 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5080 ERR("called but we don't have FreeType\n");
5084 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5087 ERR("called but we don't have FreeType\n");
5091 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5092 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5094 ERR("called but we don't have FreeType\n");
5098 BOOL
WineEngGetTextExtentPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5101 ERR("called but we don't have FreeType\n");
5105 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5108 ERR("called but we don't have FreeType\n");
5112 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5114 ERR("called but we don't have FreeType\n");
5118 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5124 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5130 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
5136 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5139 return DEFAULT_CHARSET
;
5142 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5147 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5149 FIXME("(%p, %p): stub\n", font
, glyphset
);
5153 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5158 /*************************************************************************
5159 * GetRasterizerCaps (GDI32.@)
5161 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5163 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5165 lprs
->nLanguageID
= 0;
5169 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5171 ERR("called but we don't have FreeType\n");
5175 #endif /* HAVE_FREETYPE */