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
;
262 /* Cached data for Enum */
265 NEWTEXTMETRICEXW ntm
;
269 typedef struct tagFamily
{
271 const WCHAR
*FamilyName
;
277 INT adv
; /* These three hold to widths of the unrotated chars */
295 typedef struct tagHFONTLIST
{
309 struct font_mapping
*mapping
;
320 struct list hfontlist
;
325 OUTLINETEXTMETRICW
*potm
;
327 DWORD total_kern_pairs
;
328 KERNINGPAIR
*kern_pairs
;
331 struct list child_fonts
;
337 const WCHAR
*font_name
;
341 #define GM_BLOCK_SIZE 128
342 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
344 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
345 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
346 #define UNUSED_CACHE_SIZE 10
347 static struct list child_font_list
= LIST_INIT(child_font_list
);
348 static struct list system_links
= LIST_INIT(system_links
);
350 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
352 static struct list font_list
= LIST_INIT(font_list
);
354 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
355 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
356 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
358 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
360 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
361 static const WCHAR win9x_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','\\',
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 winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
367 'W','i','n','d','o','w','s',' ','N','T','\\',
368 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
369 'F','o','n','t','s','\0'};
371 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
372 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
373 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
374 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
376 static const WCHAR
* const SystemFontValues
[4] = {
383 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
384 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
386 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
387 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
388 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
389 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
390 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
391 'E','u','r','o','p','e','a','n','\0'};
392 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
393 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
394 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
395 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
396 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
397 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
398 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
399 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
400 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
401 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
402 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
403 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
405 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
415 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
423 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
432 typedef struct tagFontSubst
{
448 static struct list mappings_list
= LIST_INIT( mappings_list
);
450 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
452 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
454 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
456 /****************************************
457 * Notes on .fon files
459 * The fonts System, FixedSys and Terminal are special. There are typically multiple
460 * versions installed for different resolutions and codepages. Windows stores which one to use
461 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
463 * FIXEDFON.FON FixedSys
465 * OEMFONT.FON Terminal
466 * LogPixels Current dpi set by the display control panel applet
467 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
468 * also has a LogPixels value that appears to mirror this)
470 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
471 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
472 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
473 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
474 * so that makes sense.
476 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
477 * to be mapped into the registry on Windows 2000 at least).
480 * ega80woa.fon=ega80850.fon
481 * ega40woa.fon=ega40850.fon
482 * cga80woa.fon=cga80850.fon
483 * cga40woa.fon=cga40850.fon
486 #ifdef HAVE_CARBON_CARBON_H
487 static char *find_cache_dir(void)
491 static char cached_path
[MAX_PATH
];
492 static const char *wine
= "/Wine", *fonts
= "/Fonts";
494 if(*cached_path
) return cached_path
;
496 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
499 WARN("can't create cached data folder\n");
502 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
505 WARN("can't create cached data path\n");
509 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
511 ERR("Could not create full path\n");
515 strcat(cached_path
, wine
);
517 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
519 WARN("Couldn't mkdir %s\n", cached_path
);
523 strcat(cached_path
, fonts
);
524 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
526 WARN("Couldn't mkdir %s\n", cached_path
);
533 /******************************************************************
536 * Extracts individual TrueType font files from a Mac suitcase font
537 * and saves them into the user's caches directory (see
539 * Returns a NULL terminated array of filenames.
541 * We do this because they are apps that try to read ttf files
542 * themselves and they don't like Mac suitcase files.
544 static char **expand_mac_font(const char *path
)
551 const char *filename
;
555 unsigned int size
, max_size
;
558 TRACE("path %s\n", path
);
560 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
563 WARN("failed to get ref\n");
567 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
570 TRACE("no data fork, so trying resource fork\n");
571 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
574 TRACE("unable to open resource fork\n");
581 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
584 CloseResFile(res_ref
);
588 out_dir
= find_cache_dir();
590 filename
= strrchr(path
, '/');
591 if(!filename
) filename
= path
;
594 /* output filename has the form out_dir/filename_%04x.ttf */
595 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
602 unsigned short *num_faces_ptr
, num_faces
, face
;
605 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
607 fond
= Get1IndResource(fond_res
, idx
);
609 TRACE("got fond resource %d\n", idx
);
612 fam_rec
= *(FamRec
**)fond
;
613 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
614 num_faces
= GET_BE_WORD(*num_faces_ptr
);
616 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
617 TRACE("num faces %04x\n", num_faces
);
618 for(face
= 0; face
< num_faces
; face
++, assoc
++)
621 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
622 unsigned short size
, font_id
;
625 size
= GET_BE_WORD(assoc
->fontSize
);
626 font_id
= GET_BE_WORD(assoc
->fontID
);
629 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
633 TRACE("trying to load sfnt id %04x\n", font_id
);
634 sfnt
= GetResource(sfnt_res
, font_id
);
637 TRACE("can't get sfnt resource %04x\n", font_id
);
641 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
646 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
648 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
649 if(fd
!= -1 || errno
== EEXIST
)
653 unsigned char *sfnt_data
;
656 sfnt_data
= *(unsigned char**)sfnt
;
657 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
661 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
664 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
666 ret
.array
[ret
.size
++] = output
;
670 WARN("unable to create %s\n", output
);
671 HeapFree(GetProcessHeap(), 0, output
);
674 ReleaseResource(sfnt
);
677 ReleaseResource(fond
);
680 CloseResFile(res_ref
);
685 #endif /* HAVE_CARBON_CARBON_H */
687 static inline BOOL
is_win9x(void)
689 return GetVersion() & 0x80000000;
692 This function builds an FT_Fixed from a float. It puts the integer part
693 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
694 It fails if the integer part of the float number is greater than SHORT_MAX.
696 static inline FT_Fixed
FT_FixedFromFloat(float f
)
699 unsigned short fract
= (f
- value
) * 0xFFFF;
700 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
704 This function builds an FT_Fixed from a FIXED. It simply put f.value
705 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
707 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
709 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
713 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
718 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
719 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
721 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
722 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
724 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
726 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
728 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
732 file
= strrchr(face
->file
, '/');
737 if(!strcasecmp(file
, file_nameA
))
739 HeapFree(GetProcessHeap(), 0, file_nameA
);
744 HeapFree(GetProcessHeap(), 0, file_nameA
);
748 static Family
*find_family_from_name(const WCHAR
*name
)
752 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
754 if(!strcmpiW(family
->FamilyName
, name
))
761 static void DumpSubstList(void)
765 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
767 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
768 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
769 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
771 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
772 debugstr_w(psub
->to
.name
));
777 static LPWSTR
strdupW(LPCWSTR p
)
780 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
781 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
786 static LPSTR
strdupA(LPCSTR p
)
789 DWORD len
= (strlen(p
) + 1);
790 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
795 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
800 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
802 if(!strcmpiW(element
->from
.name
, from_name
) &&
803 (element
->from
.charset
== from_charset
||
804 element
->from
.charset
== -1))
811 #define ADD_FONT_SUBST_FORCE 1
813 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
815 FontSubst
*from_exist
, *to_exist
;
817 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
819 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
821 list_remove(&from_exist
->entry
);
822 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
823 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
824 HeapFree(GetProcessHeap(), 0, from_exist
);
830 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
834 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
835 subst
->to
.name
= strdupW(to_exist
->to
.name
);
838 list_add_tail(subst_list
, &subst
->entry
);
843 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
844 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
845 HeapFree(GetProcessHeap(), 0, subst
);
849 static void split_subst_info(NameCs
*nc
, LPSTR str
)
851 CHAR
*p
= strrchr(str
, ',');
856 nc
->charset
= strtol(p
+1, NULL
, 10);
859 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
860 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
861 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
864 static void LoadSubstList(void)
868 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
872 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
873 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
874 &hkey
) == ERROR_SUCCESS
) {
876 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
877 &valuelen
, &datalen
, NULL
, NULL
);
879 valuelen
++; /* returned value doesn't include room for '\0' */
880 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
881 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
885 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
886 &dlen
) == ERROR_SUCCESS
) {
887 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
889 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
890 split_subst_info(&psub
->from
, value
);
891 split_subst_info(&psub
->to
, data
);
893 /* Win 2000 doesn't allow mapping between different charsets
894 or mapping of DEFAULT_CHARSET */
895 if((psub
->to
.charset
!= psub
->from
.charset
) ||
896 psub
->to
.charset
== DEFAULT_CHARSET
) {
897 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
898 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
899 HeapFree(GetProcessHeap(), 0, psub
);
901 add_font_subst(&font_subst_list
, psub
, 0);
903 /* reset dlen and vlen */
907 HeapFree(GetProcessHeap(), 0, data
);
908 HeapFree(GetProcessHeap(), 0, value
);
913 static WCHAR
*get_familyname(FT_Face ft_face
)
915 WCHAR
*family
= NULL
;
917 FT_UInt num_names
, name_index
, i
;
919 if(FT_IS_SFNT(ft_face
))
921 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
923 for(name_index
= 0; name_index
< num_names
; name_index
++)
925 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
927 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
928 (name
.language_id
== GetUserDefaultLCID()) &&
929 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
930 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
932 /* String is not nul terminated and string_len is a byte length. */
933 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
934 for(i
= 0; i
< name
.string_len
/ 2; i
++)
936 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
937 family
[i
] = GET_BE_WORD(*tmp
);
941 TRACE("Got localised name %s\n", debugstr_w(family
));
952 /*****************************************************************
955 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
956 * of FreeType that don't export this function.
959 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
964 /* If the FT_Load_Sfnt_Table function is there we'll use it */
965 if(pFT_Load_Sfnt_Table
)
967 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
969 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
970 else /* Do it the hard way */
972 TT_Face tt_face
= (TT_Face
) ft_face
;
973 SFNT_Interface
*sfnt
;
974 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
977 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
981 /* A field was added in the middle of the structure in 2.1.x */
982 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
984 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
992 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
993 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
994 "Please upgrade your freetype library.\n");
997 err
= FT_Err_Unimplemented_Feature
;
1004 #define ADDFONT_EXTERNAL_FONT 0x01
1005 #define ADDFONT_FORCE_BITMAP 0x02
1006 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1010 TT_Header
*pHeader
= NULL
;
1011 WCHAR
*english_family
, *localised_family
, *StyleW
;
1015 struct list
*family_elem_ptr
, *face_elem_ptr
;
1017 FT_Long face_index
= 0, num_faces
;
1018 #ifdef HAVE_FREETYPE_FTWINFNT_H
1019 FT_WinFNT_HeaderRec winfnt_header
;
1021 int i
, bitmap_num
, internal_leading
;
1024 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1025 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1027 #ifdef HAVE_CARBON_CARBON_H
1028 if(file
&& !fake_family
)
1030 char **mac_list
= expand_mac_font(file
);
1033 BOOL had_one
= FALSE
;
1035 for(cursor
= mac_list
; *cursor
; cursor
++)
1038 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1039 HeapFree(GetProcessHeap(), 0, *cursor
);
1041 HeapFree(GetProcessHeap(), 0, mac_list
);
1046 #endif /* HAVE_CARBON_CARBON_H */
1049 char *family_name
= fake_family
;
1053 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1054 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1057 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1058 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1062 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1066 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*/
1067 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1068 pFT_Done_Face(ft_face
);
1072 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1073 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1074 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1075 pFT_Done_Face(ft_face
);
1079 if(FT_IS_SFNT(ft_face
))
1081 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1082 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1083 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1085 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1086 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1087 pFT_Done_Face(ft_face
);
1091 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1092 we don't want to load these. */
1093 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1097 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1099 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1100 pFT_Done_Face(ft_face
);
1106 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1107 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1108 pFT_Done_Face(ft_face
);
1114 localised_family
= get_familyname(ft_face
);
1115 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1117 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1118 HeapFree(GetProcessHeap(), 0, localised_family
);
1119 num_faces
= ft_face
->num_faces
;
1120 pFT_Done_Face(ft_face
);
1123 HeapFree(GetProcessHeap(), 0, localised_family
);
1127 family_name
= ft_face
->family_name
;
1131 My_FT_Bitmap_Size
*size
= NULL
;
1134 if(!FT_IS_SCALABLE(ft_face
))
1135 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1137 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1138 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1139 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1141 localised_family
= NULL
;
1143 localised_family
= get_familyname(ft_face
);
1144 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1145 HeapFree(GetProcessHeap(), 0, localised_family
);
1146 localised_family
= NULL
;
1151 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1152 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1153 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1158 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1159 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1160 list_init(&family
->faces
);
1161 list_add_tail(&font_list
, &family
->entry
);
1163 if(localised_family
) {
1164 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1165 subst
->from
.name
= strdupW(english_family
);
1166 subst
->from
.charset
= -1;
1167 subst
->to
.name
= strdupW(localised_family
);
1168 subst
->to
.charset
= -1;
1169 add_font_subst(&font_subst_list
, subst
, 0);
1172 HeapFree(GetProcessHeap(), 0, localised_family
);
1173 HeapFree(GetProcessHeap(), 0, english_family
);
1175 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1176 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1177 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1179 internal_leading
= 0;
1180 memset(&fs
, 0, sizeof(fs
));
1182 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1184 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1185 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1186 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1187 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1188 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1189 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1190 if(pOS2
->version
== 0) {
1193 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1196 fs
.fsCsb
[0] |= 1L << 31;
1199 #ifdef HAVE_FREETYPE_FTWINFNT_H
1200 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1202 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1203 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1204 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1205 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
1206 internal_leading
= winfnt_header
.internal_leading
;
1210 face_elem_ptr
= list_head(&family
->faces
);
1211 while(face_elem_ptr
) {
1212 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1213 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1214 if(!strcmpW(face
->StyleName
, StyleW
) &&
1215 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1216 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1217 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1218 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1221 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1222 HeapFree(GetProcessHeap(), 0, StyleW
);
1223 pFT_Done_Face(ft_face
);
1226 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1227 TRACE("Original font is newer so skipping this one\n");
1228 HeapFree(GetProcessHeap(), 0, StyleW
);
1229 pFT_Done_Face(ft_face
);
1232 TRACE("Replacing original with this one\n");
1233 list_remove(&face
->entry
);
1234 HeapFree(GetProcessHeap(), 0, face
->file
);
1235 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1236 HeapFree(GetProcessHeap(), 0, face
);
1241 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1242 face
->cache_valid
= FALSE
;
1243 list_add_tail(&family
->faces
, &face
->entry
);
1244 face
->StyleName
= StyleW
;
1247 face
->file
= strdupA(file
);
1248 face
->font_data_ptr
= NULL
;
1249 face
->font_data_size
= 0;
1254 face
->font_data_ptr
= font_data_ptr
;
1255 face
->font_data_size
= font_data_size
;
1257 face
->face_index
= face_index
;
1258 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
1259 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
1260 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1261 face
->family
= family
;
1262 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1263 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
1264 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1266 if(FT_IS_SCALABLE(ft_face
)) {
1267 memset(&face
->size
, 0, sizeof(face
->size
));
1268 face
->scalable
= TRUE
;
1270 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1271 size
->height
, size
->width
, size
->size
>> 6,
1272 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1273 face
->size
.height
= size
->height
;
1274 face
->size
.width
= size
->width
;
1275 face
->size
.size
= size
->size
;
1276 face
->size
.x_ppem
= size
->x_ppem
;
1277 face
->size
.y_ppem
= size
->y_ppem
;
1278 face
->size
.internal_leading
= internal_leading
;
1279 face
->scalable
= FALSE
;
1282 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1284 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1286 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1287 face
->ntmFlags
= NTM_PS_OPENTYPE
;
1292 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1293 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1294 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1295 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1298 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1299 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1300 switch(ft_face
->charmaps
[i
]->encoding
) {
1301 case FT_ENCODING_UNICODE
:
1302 case FT_ENCODING_APPLE_ROMAN
:
1303 face
->fs
.fsCsb
[0] |= 1;
1305 case FT_ENCODING_MS_SYMBOL
:
1306 face
->fs
.fsCsb
[0] |= 1L << 31;
1314 if(face
->fs
.fsCsb
[0] & ~(1L << 31))
1315 have_installed_roman_font
= TRUE
;
1316 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1318 num_faces
= ft_face
->num_faces
;
1319 pFT_Done_Face(ft_face
);
1320 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1321 debugstr_w(StyleW
));
1322 } while(num_faces
> ++face_index
);
1326 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1328 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1331 static void DumpFontList(void)
1335 struct list
*family_elem_ptr
, *face_elem_ptr
;
1337 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1338 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1339 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1340 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1341 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1342 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1344 TRACE(" %d", face
->size
.height
);
1351 /***********************************************************
1352 * The replacement list is a way to map an entire font
1353 * family onto another family. For example adding
1355 * [HKCU\Software\Wine\Fonts\Replacements]
1356 * "Wingdings"="Winedings"
1358 * would enumerate the Winedings font both as Winedings and
1359 * Wingdings. However if a real Wingdings font is present the
1360 * replacement does not take place.
1363 static void LoadReplaceList(void)
1366 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1371 struct list
*family_elem_ptr
, *face_elem_ptr
;
1374 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1375 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1377 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1378 &valuelen
, &datalen
, NULL
, NULL
);
1380 valuelen
++; /* returned value doesn't include room for '\0' */
1381 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1382 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1386 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1387 &dlen
) == ERROR_SUCCESS
) {
1388 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1389 /* "NewName"="Oldname" */
1390 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1392 /* Find the old family and hence all of the font files
1394 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1395 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1396 if(!strcmpiW(family
->FamilyName
, data
)) {
1397 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1398 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1399 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1400 debugstr_w(face
->StyleName
), familyA
);
1401 /* Now add a new entry with the new family name */
1402 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1407 /* reset dlen and vlen */
1411 HeapFree(GetProcessHeap(), 0, data
);
1412 HeapFree(GetProcessHeap(), 0, value
);
1417 /*************************************************************
1420 static BOOL
init_system_links(void)
1422 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1423 'W','i','n','d','o','w','s',' ','N','T','\\',
1424 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1425 'S','y','s','t','e','m','L','i','n','k',0};
1428 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1429 WCHAR
*value
, *data
;
1430 WCHAR
*entry
, *next
;
1431 SYSTEM_LINKS
*font_link
, *system_font_link
;
1432 CHILD_FONT
*child_font
;
1433 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1434 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1435 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1441 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1443 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1444 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1445 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1446 val_len
= max_val
+ 1;
1447 data_len
= max_data
;
1449 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1451 TRACE("%s:\n", debugstr_w(value
));
1453 memset(&fs
, 0, sizeof(fs
));
1454 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1455 psub
= get_font_subst(&font_subst_list
, value
, -1);
1456 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1457 list_init(&font_link
->links
);
1458 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1461 CHILD_FONT
*child_font
;
1463 TRACE("\t%s\n", debugstr_w(entry
));
1465 next
= entry
+ strlenW(entry
) + 1;
1467 face_name
= strchrW(entry
, ',');
1471 while(isspaceW(*face_name
))
1474 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1476 face_name
= psub
->to
.name
;
1478 face
= find_face_from_filename(entry
, face_name
);
1481 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1485 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1486 child_font
->face
= face
;
1487 child_font
->font
= NULL
;
1488 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1489 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1490 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1491 list_add_tail(&font_link
->links
, &child_font
->entry
);
1493 family
= find_family_from_name(font_link
->font_name
);
1496 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1498 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
1501 list_add_tail(&system_links
, &font_link
->entry
);
1502 val_len
= max_val
+ 1;
1503 data_len
= max_data
;
1506 HeapFree(GetProcessHeap(), 0, value
);
1507 HeapFree(GetProcessHeap(), 0, data
);
1511 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1514 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1515 system_font_link
->font_name
= strdupW(System
);
1516 list_init(&system_font_link
->links
);
1518 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1521 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1522 child_font
->face
= face
;
1523 child_font
->font
= NULL
;
1524 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1525 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1527 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1529 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1531 CHILD_FONT
*font_link_entry
;
1532 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1534 CHILD_FONT
*new_child
;
1535 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1536 new_child
->face
= font_link_entry
->face
;
1537 new_child
->font
= NULL
;
1538 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1543 list_add_tail(&system_links
, &system_font_link
->entry
);
1547 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1550 struct dirent
*dent
;
1551 char path
[MAX_PATH
];
1553 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1555 dir
= opendir(dirname
);
1557 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1560 while((dent
= readdir(dir
)) != NULL
) {
1561 struct stat statbuf
;
1563 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1566 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1568 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1570 if(stat(path
, &statbuf
) == -1)
1572 WARN("Can't stat %s\n", debugstr_a(path
));
1575 if(S_ISDIR(statbuf
.st_mode
))
1576 ReadFontDir(path
, external_fonts
);
1578 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1584 static void load_fontconfig_fonts(void)
1586 #ifdef SONAME_LIBFONTCONFIG
1587 void *fc_handle
= NULL
;
1596 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1598 TRACE("Wine cannot find the fontconfig library (%s).\n",
1599 SONAME_LIBFONTCONFIG
);
1602 #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;}
1603 LOAD_FUNCPTR(FcConfigGetCurrent
);
1604 LOAD_FUNCPTR(FcFontList
);
1605 LOAD_FUNCPTR(FcFontSetDestroy
);
1606 LOAD_FUNCPTR(FcInit
);
1607 LOAD_FUNCPTR(FcObjectSetAdd
);
1608 LOAD_FUNCPTR(FcObjectSetCreate
);
1609 LOAD_FUNCPTR(FcObjectSetDestroy
);
1610 LOAD_FUNCPTR(FcPatternCreate
);
1611 LOAD_FUNCPTR(FcPatternDestroy
);
1612 LOAD_FUNCPTR(FcPatternGetBool
);
1613 LOAD_FUNCPTR(FcPatternGetString
);
1616 if(!pFcInit()) return;
1618 config
= pFcConfigGetCurrent();
1619 pat
= pFcPatternCreate();
1620 os
= pFcObjectSetCreate();
1621 pFcObjectSetAdd(os
, FC_FILE
);
1622 pFcObjectSetAdd(os
, FC_SCALABLE
);
1623 fontset
= pFcFontList(config
, pat
, os
);
1624 if(!fontset
) return;
1625 for(i
= 0; i
< fontset
->nfont
; i
++) {
1628 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1630 TRACE("fontconfig: %s\n", file
);
1632 /* We're just interested in OT/TT fonts for now, so this hack just
1633 picks up the scalable fonts without extensions .pf[ab] to save time
1634 loading every other font */
1636 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1638 TRACE("not scalable\n");
1642 len
= strlen( file
);
1643 if(len
< 4) continue;
1644 ext
= &file
[ len
- 3 ];
1645 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1646 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1648 pFcFontSetDestroy(fontset
);
1649 pFcObjectSetDestroy(os
);
1650 pFcPatternDestroy(pat
);
1656 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1659 const char *data_dir
= wine_get_data_dir();
1661 if (!data_dir
) data_dir
= wine_get_build_dir();
1668 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1670 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1672 strcpy(unix_name
, data_dir
);
1673 strcat(unix_name
, "/fonts/");
1675 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1677 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1678 HeapFree(GetProcessHeap(), 0, unix_name
);
1683 static void load_system_fonts(void)
1686 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1687 const WCHAR
* const *value
;
1689 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1692 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1693 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1694 strcatW(windowsdir
, fontsW
);
1695 for(value
= SystemFontValues
; *value
; value
++) {
1696 dlen
= sizeof(data
);
1697 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1701 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1702 if((unixname
= wine_get_unix_file_name(pathW
))) {
1703 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1704 HeapFree(GetProcessHeap(), 0, unixname
);
1707 load_font_from_data_dir(data
);
1714 /*************************************************************
1716 * This adds registry entries for any externally loaded fonts
1717 * (fonts from fontconfig or FontDirs). It also deletes entries
1718 * of no longer existing fonts.
1721 static void update_reg_entries(void)
1723 HKEY winkey
= 0, externalkey
= 0;
1726 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
1729 struct list
*family_elem_ptr
, *face_elem_ptr
;
1731 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1732 static const WCHAR spaceW
[] = {' ', '\0'};
1735 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1736 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
1737 ERR("Can't create Windows font reg key\n");
1740 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1741 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
1742 ERR("Can't create external font reg key\n");
1746 /* Delete all external fonts added last time */
1748 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1749 &valuelen
, &datalen
, NULL
, NULL
);
1750 valuelen
++; /* returned value doesn't include room for '\0' */
1751 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1752 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1754 dlen
= datalen
* sizeof(WCHAR
);
1757 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1758 &dlen
) == ERROR_SUCCESS
) {
1760 RegDeleteValueW(winkey
, valueW
);
1761 /* reset dlen and vlen */
1765 HeapFree(GetProcessHeap(), 0, data
);
1766 HeapFree(GetProcessHeap(), 0, valueW
);
1768 /* Delete the old external fonts key */
1769 RegCloseKey(externalkey
);
1771 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1773 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1774 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1775 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
1776 ERR("Can't create external font reg key\n");
1780 /* enumerate the fonts and add external ones to the two keys */
1782 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1783 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1784 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1785 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1786 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1787 if(!face
->external
) continue;
1789 if(strcmpiW(face
->StyleName
, RegularW
))
1790 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1791 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1792 strcpyW(valueW
, family
->FamilyName
);
1793 if(len
!= len_fam
) {
1794 strcatW(valueW
, spaceW
);
1795 strcatW(valueW
, face
->StyleName
);
1797 strcatW(valueW
, TrueType
);
1798 if((path
= strrchr(face
->file
, '/')) == NULL
)
1802 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1804 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1805 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1806 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1807 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1809 HeapFree(GetProcessHeap(), 0, file
);
1810 HeapFree(GetProcessHeap(), 0, valueW
);
1815 RegCloseKey(externalkey
);
1817 RegCloseKey(winkey
);
1822 /*************************************************************
1823 * WineEngAddFontResourceEx
1826 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1828 if (ft_handle
) /* do it only if we have freetype up and running */
1833 FIXME("Ignoring flags %x\n", flags
);
1835 if((unixname
= wine_get_unix_file_name(file
)))
1837 INT ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1838 HeapFree(GetProcessHeap(), 0, unixname
);
1845 /*************************************************************
1846 * WineEngAddFontMemResourceEx
1849 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
1851 if (ft_handle
) /* do it only if we have freetype up and running */
1853 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
1855 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
1856 memcpy(pFontCopy
, pbFont
, cbFont
);
1858 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1862 TRACE("AddFontToList failed\n");
1863 HeapFree(GetProcessHeap(), 0, pFontCopy
);
1866 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1867 * For now return something unique but quite random
1869 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
1870 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
1877 /*************************************************************
1878 * WineEngRemoveFontResourceEx
1881 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1887 static const struct nls_update_font_list
1889 UINT ansi_cp
, oem_cp
;
1890 const char *oem
, *fixed
, *system
;
1891 const char *courier
, *serif
, *small
, *sserif
;
1892 /* these are for font substitute */
1893 const char *shelldlg
, *tmsrmn
;
1894 } nls_update_font_list
[] =
1896 /* Latin 1 (United States) */
1897 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1898 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1899 "Tahoma","Times New Roman",
1901 /* Latin 1 (Multilingual) */
1902 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1903 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1904 "Tahoma","Times New Roman", /* FIXME unverified */
1906 /* Eastern Europe */
1907 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1908 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1909 "Tahoma","Times New Roman", /* FIXME unverified */
1912 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1913 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1914 "Tahoma","Times New Roman", /* FIXME unverified */
1917 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1918 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1919 "Tahoma","Times New Roman", /* FIXME unverified */
1922 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1923 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1924 "Tahoma","Times New Roman", /* FIXME unverified */
1927 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1928 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1929 "Tahoma","Times New Roman", /* FIXME unverified */
1932 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1933 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1934 "Tahoma","Times New Roman", /* FIXME unverified */
1937 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1938 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1939 "Tahoma","Times New Roman", /* FIXME unverified */
1942 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1943 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1944 "Tahoma","Times New Roman", /* FIXME unverified */
1947 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1948 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1949 "Tahoma","Times New Roman", /* FIXME unverified */
1952 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1953 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1954 "MS UI Gothic","MS Serif",
1956 /* Chinese Simplified */
1957 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1958 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1959 "Tahoma", "Times New Roman", /* FIXME unverified */
1962 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1963 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1966 /* Chinese Traditional */
1967 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1968 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1969 "Tahoma", "Times New Roman", /* FIXME unverified */
1973 static inline HKEY
create_fonts_NT_registry_key(void)
1977 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
1978 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1982 static inline HKEY
create_fonts_9x_registry_key(void)
1986 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
1987 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1991 static inline HKEY
create_config_fonts_registry_key(void)
1995 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
1996 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2000 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2002 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2003 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2004 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2005 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2008 static void update_font_info(void)
2010 char buf
[40], cpbuf
[40];
2013 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2015 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2018 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2019 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2020 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2021 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2022 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2025 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2027 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2032 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2034 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2036 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2039 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2041 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2042 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2046 hkey
= create_config_fonts_registry_key();
2047 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2048 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2049 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2052 hkey
= create_fonts_NT_registry_key();
2053 add_font_list(hkey
, &nls_update_font_list
[i
]);
2056 hkey
= create_fonts_9x_registry_key();
2057 add_font_list(hkey
, &nls_update_font_list
[i
]);
2060 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2062 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2063 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2064 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2065 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2071 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2074 /*************************************************************
2077 * Initialize FreeType library and create a list of available faces
2079 BOOL
WineEngInit(void)
2081 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2082 static const WCHAR pathW
[] = {'P','a','t','h',0};
2084 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2086 WCHAR windowsdir
[MAX_PATH
];
2089 const char *data_dir
;
2093 /* update locale dependent font info in registry */
2096 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2099 "Wine cannot find the FreeType font library. To enable Wine to\n"
2100 "use TrueType fonts please install a version of FreeType greater than\n"
2101 "or equal to 2.0.5.\n"
2102 "http://www.freetype.org\n");
2106 #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;}
2108 LOAD_FUNCPTR(FT_Vector_Unit
)
2109 LOAD_FUNCPTR(FT_Done_Face
)
2110 LOAD_FUNCPTR(FT_Get_Char_Index
)
2111 LOAD_FUNCPTR(FT_Get_Module
)
2112 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2113 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2114 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2115 LOAD_FUNCPTR(FT_Init_FreeType
)
2116 LOAD_FUNCPTR(FT_Load_Glyph
)
2117 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2118 LOAD_FUNCPTR(FT_MulFix
)
2119 LOAD_FUNCPTR(FT_New_Face
)
2120 LOAD_FUNCPTR(FT_New_Memory_Face
)
2121 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2122 LOAD_FUNCPTR(FT_Outline_Transform
)
2123 LOAD_FUNCPTR(FT_Outline_Translate
)
2124 LOAD_FUNCPTR(FT_Select_Charmap
)
2125 LOAD_FUNCPTR(FT_Set_Charmap
)
2126 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2127 LOAD_FUNCPTR(FT_Vector_Transform
)
2130 /* Don't warn if this one is missing */
2131 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2132 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2133 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2134 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2135 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2136 #ifdef HAVE_FREETYPE_FTWINFNT_H
2137 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2139 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2140 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2141 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2142 <= 2.0.3 has FT_Sqrt64 */
2146 if(pFT_Init_FreeType(&library
) != 0) {
2147 ERR("Can't init FreeType library\n");
2148 wine_dlclose(ft_handle
, NULL
, 0);
2152 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
2153 if (pFT_Library_Version
)
2155 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2157 if (FT_Version
.major
<=0)
2163 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2164 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2165 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2166 ((FT_Version
.patch
) & 0x0000ff);
2168 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2169 ERR("Failed to create font mutex\n");
2172 WaitForSingleObject(font_mutex
, INFINITE
);
2174 /* load the system bitmap fonts */
2175 load_system_fonts();
2177 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2178 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2179 strcatW(windowsdir
, fontsW
);
2180 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2182 ReadFontDir(unixname
, FALSE
);
2183 HeapFree(GetProcessHeap(), 0, unixname
);
2186 /* load the system truetype fonts */
2187 data_dir
= wine_get_data_dir();
2188 if (!data_dir
) data_dir
= wine_get_build_dir();
2189 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2190 strcpy(unixname
, data_dir
);
2191 strcat(unixname
, "/fonts/");
2192 ReadFontDir(unixname
, TRUE
);
2193 HeapFree(GetProcessHeap(), 0, unixname
);
2196 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2197 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2198 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2200 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2201 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2202 &hkey
) == ERROR_SUCCESS
) {
2204 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2205 &valuelen
, &datalen
, NULL
, NULL
);
2207 valuelen
++; /* returned value doesn't include room for '\0' */
2208 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2209 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2212 dlen
= datalen
* sizeof(WCHAR
);
2214 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2215 &dlen
) == ERROR_SUCCESS
) {
2216 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2218 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2220 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2221 HeapFree(GetProcessHeap(), 0, unixname
);
2224 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2226 WCHAR pathW
[MAX_PATH
];
2227 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2230 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2231 if((unixname
= wine_get_unix_file_name(pathW
)))
2233 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2234 HeapFree(GetProcessHeap(), 0, unixname
);
2237 load_font_from_data_dir(data
);
2239 /* reset dlen and vlen */
2244 HeapFree(GetProcessHeap(), 0, data
);
2245 HeapFree(GetProcessHeap(), 0, valueW
);
2249 load_fontconfig_fonts();
2251 /* then look in any directories that we've specified in the config file */
2252 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2253 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2259 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2261 len
+= sizeof(WCHAR
);
2262 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2263 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2265 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2266 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2267 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2268 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2272 LPSTR next
= strchr( ptr
, ':' );
2273 if (next
) *next
++ = 0;
2274 ReadFontDir( ptr
, TRUE
);
2277 HeapFree( GetProcessHeap(), 0, valueA
);
2279 HeapFree( GetProcessHeap(), 0, valueW
);
2288 update_reg_entries();
2290 init_system_links();
2292 ReleaseMutex(font_mutex
);
2296 "Wine cannot find certain functions that it needs inside the FreeType\n"
2297 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2298 "FreeType to at least version 2.0.5.\n"
2299 "http://www.freetype.org\n");
2300 wine_dlclose(ft_handle
, NULL
, 0);
2306 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2309 TT_HoriHeader
*pHori
;
2313 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2314 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2316 if(height
== 0) height
= 16;
2318 /* Calc. height of EM square:
2320 * For +ve lfHeight we have
2321 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2322 * Re-arranging gives:
2323 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2325 * For -ve lfHeight we have
2327 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2328 * with il = winAscent + winDescent - units_per_em]
2333 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2334 ppem
= ft_face
->units_per_EM
* height
/
2335 (pHori
->Ascender
- pHori
->Descender
);
2337 ppem
= ft_face
->units_per_EM
* height
/
2338 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2346 static struct font_mapping
*map_font_file( const char *name
)
2348 struct font_mapping
*mapping
;
2352 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2353 if (fstat( fd
, &st
) == -1) goto error
;
2355 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2357 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2359 mapping
->refcount
++;
2364 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2367 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2370 if (mapping
->data
== MAP_FAILED
)
2372 HeapFree( GetProcessHeap(), 0, mapping
);
2375 mapping
->refcount
= 1;
2376 mapping
->dev
= st
.st_dev
;
2377 mapping
->ino
= st
.st_ino
;
2378 mapping
->size
= st
.st_size
;
2379 list_add_tail( &mappings_list
, &mapping
->entry
);
2387 static void unmap_font_file( struct font_mapping
*mapping
)
2389 if (!--mapping
->refcount
)
2391 list_remove( &mapping
->entry
);
2392 munmap( mapping
->data
, mapping
->size
);
2393 HeapFree( GetProcessHeap(), 0, mapping
);
2397 static LONG
load_VDMX(GdiFont
*, LONG
);
2399 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2406 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2410 if (!(font
->mapping
= map_font_file( face
->file
)))
2412 WARN("failed to map %s\n", debugstr_a(face
->file
));
2415 data_ptr
= font
->mapping
->data
;
2416 data_size
= font
->mapping
->size
;
2420 data_ptr
= face
->font_data_ptr
;
2421 data_size
= face
->font_data_size
;
2424 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2426 ERR("FT_New_Face rets %d\n", err
);
2430 /* set it here, as load_VDMX needs it */
2431 font
->ft_face
= ft_face
;
2433 if(FT_IS_SCALABLE(ft_face
)) {
2434 /* load the VDMX table if we have one */
2435 font
->ppem
= load_VDMX(font
, height
);
2437 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2439 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2440 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2442 font
->ppem
= height
;
2443 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2444 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2450 static int get_nearest_charset(Face
*face
, int *cp
)
2452 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2453 a single face with the requested charset. The idea is to check if
2454 the selected font supports the current ANSI codepage, if it does
2455 return the corresponding charset, else return the first charset */
2458 int acp
= GetACP(), i
;
2462 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2463 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2464 return csi
.ciCharset
;
2466 for(i
= 0; i
< 32; i
++) {
2468 if(face
->fs
.fsCsb
[0] & fs0
) {
2469 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2471 return csi
.ciCharset
;
2474 FIXME("TCI failing on %x\n", fs0
);
2478 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2479 face
->fs
.fsCsb
[0], face
->file
);
2481 return DEFAULT_CHARSET
;
2484 static GdiFont
*alloc_font(void)
2486 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2488 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2489 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2491 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2492 ret
->total_kern_pairs
= (DWORD
)-1;
2493 ret
->kern_pairs
= NULL
;
2494 list_init(&ret
->hfontlist
);
2495 list_init(&ret
->child_fonts
);
2499 static void free_font(GdiFont
*font
)
2501 struct list
*cursor
, *cursor2
;
2504 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2506 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2507 struct list
*first_hfont
;
2508 HFONTLIST
*hfontlist
;
2509 list_remove(cursor
);
2512 first_hfont
= list_head(&child
->font
->hfontlist
);
2513 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2514 DeleteObject(hfontlist
->hfont
);
2515 HeapFree(GetProcessHeap(), 0, hfontlist
);
2516 free_font(child
->font
);
2518 HeapFree(GetProcessHeap(), 0, child
);
2521 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2522 if (font
->mapping
) unmap_font_file( font
->mapping
);
2523 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2524 HeapFree(GetProcessHeap(), 0, font
->potm
);
2525 HeapFree(GetProcessHeap(), 0, font
->name
);
2526 for (i
= 0; i
< font
->gmsize
; i
++)
2527 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2528 HeapFree(GetProcessHeap(), 0, font
->gm
);
2529 HeapFree(GetProcessHeap(), 0, font
);
2533 /*************************************************************
2536 * load the vdmx entry for the specified height
2539 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2540 ( ( (FT_ULong)_x4 << 24 ) | \
2541 ( (FT_ULong)_x3 << 16 ) | \
2542 ( (FT_ULong)_x2 << 8 ) | \
2545 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2560 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2564 BYTE devXRatio
, devYRatio
;
2565 USHORT numRecs
, numRatios
;
2566 DWORD result
, offset
= -1;
2570 /* For documentation on VDMX records, see
2571 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2574 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2576 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2579 /* FIXME: need the real device aspect ratio */
2583 numRecs
= GET_BE_WORD(hdr
[1]);
2584 numRatios
= GET_BE_WORD(hdr
[2]);
2586 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2587 for(i
= 0; i
< numRatios
; i
++) {
2590 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2591 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2594 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2596 if((ratio
.xRatio
== 0 &&
2597 ratio
.yStartRatio
== 0 &&
2598 ratio
.yEndRatio
== 0) ||
2599 (devXRatio
== ratio
.xRatio
&&
2600 devYRatio
>= ratio
.yStartRatio
&&
2601 devYRatio
<= ratio
.yEndRatio
))
2603 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2604 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2605 offset
= GET_BE_WORD(tmp
);
2611 FIXME("No suitable ratio found\n");
2615 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2617 BYTE startsz
, endsz
;
2620 recs
= GET_BE_WORD(group
.recs
);
2621 startsz
= group
.startsz
;
2622 endsz
= group
.endsz
;
2624 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2626 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2627 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2628 if(result
== GDI_ERROR
) {
2629 FIXME("Failed to retrieve vTable\n");
2634 for(i
= 0; i
< recs
; i
++) {
2635 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2636 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2637 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2639 if(yMax
+ -yMin
== height
) {
2642 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2645 if(yMax
+ -yMin
> height
) {
2648 goto end
; /* failed */
2650 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2651 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2652 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2653 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2659 TRACE("ppem not found for height %d\n", height
);
2663 if(ppem
< startsz
|| ppem
> endsz
)
2666 for(i
= 0; i
< recs
; i
++) {
2668 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2670 if(yPelHeight
> ppem
)
2673 if(yPelHeight
== ppem
) {
2674 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2675 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2676 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2682 HeapFree(GetProcessHeap(), 0, vTable
);
2688 static BOOL
fontcmp(GdiFont
*font
, FONT_DESC
*fd
)
2690 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2691 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2692 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2693 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2694 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2697 static void calc_hash(FONT_DESC
*pfd
)
2699 DWORD hash
= 0, *ptr
, two_chars
;
2703 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2705 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2707 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2709 pwc
= (WCHAR
*)&two_chars
;
2711 *pwc
= toupperW(*pwc
);
2713 *pwc
= toupperW(*pwc
);
2717 hash
^= !pfd
->can_use_bitmap
;
2722 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2727 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2729 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
2730 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2731 fd
.can_use_bitmap
= can_use_bitmap
;
2734 /* try the in-use list */
2735 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2736 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2737 if(!fontcmp(ret
, &fd
)) {
2738 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2739 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2740 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2741 if(hflist
->hfont
== hfont
)
2744 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2745 hflist
->hfont
= hfont
;
2746 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2751 /* then the unused list */
2752 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2753 while(font_elem_ptr
) {
2754 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2755 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2756 if(!fontcmp(ret
, &fd
)) {
2757 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2758 assert(list_empty(&ret
->hfontlist
));
2759 TRACE("Found %p in unused list\n", ret
);
2760 list_remove(&ret
->entry
);
2761 list_add_head(&gdi_font_list
, &ret
->entry
);
2762 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2763 hflist
->hfont
= hfont
;
2764 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2772 /*************************************************************
2773 * create_child_font_list
2775 static BOOL
create_child_font_list(GdiFont
*font
)
2778 SYSTEM_LINKS
*font_link
;
2779 CHILD_FONT
*font_link_entry
, *new_child
;
2781 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2783 if(!strcmpW(font_link
->font_name
, font
->name
))
2785 TRACE("found entry in system list\n");
2786 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2788 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2789 new_child
->face
= font_link_entry
->face
;
2790 new_child
->font
= NULL
;
2791 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2792 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
2802 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2804 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2806 if (pFT_Set_Charmap
)
2809 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2811 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2813 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2815 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2817 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2818 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2820 switch (ft_face
->charmaps
[i
]->platform_id
)
2823 cmap_def
= ft_face
->charmaps
[i
];
2825 case 0: /* Apple Unicode */
2826 cmap0
= ft_face
->charmaps
[i
];
2828 case 1: /* Macintosh */
2829 cmap1
= ft_face
->charmaps
[i
];
2832 cmap2
= ft_face
->charmaps
[i
];
2834 case 3: /* Microsoft */
2835 cmap3
= ft_face
->charmaps
[i
];
2840 if (cmap3
) /* prefer Microsoft cmap table */
2841 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2843 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2845 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2847 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2849 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2851 return ft_err
== FT_Err_Ok
;
2854 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
2857 /*************************************************************
2858 * WineEngCreateFontInstance
2861 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2864 Face
*face
, *best
, *best_bitmap
;
2865 Family
*family
, *last_resort_family
;
2866 struct list
*family_elem_ptr
, *face_elem_ptr
;
2867 INT height
, width
= 0;
2868 unsigned int score
= 0, new_score
;
2869 signed int diff
= 0, newdiff
;
2870 BOOL bd
, it
, can_use_bitmap
;
2875 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2877 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2878 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2879 if(hflist
->hfont
== hfont
)
2883 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
2884 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2886 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2887 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2888 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2891 /* check the cache first */
2892 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2893 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2897 TRACE("not in cache\n");
2898 if(list_empty(&font_list
)) /* No fonts installed */
2900 TRACE("No fonts installed\n");
2903 if(!have_installed_roman_font
)
2905 TRACE("No roman font installed\n");
2911 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
2912 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
2913 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
2914 calc_hash(&ret
->font_desc
);
2915 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2916 hflist
->hfont
= hfont
;
2917 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2920 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2921 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2922 original value lfCharSet. Note this is a special case for
2923 Symbol and doesn't happen at least for "Wingdings*" */
2925 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
2926 lf
.lfCharSet
= SYMBOL_CHARSET
;
2928 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
2929 switch(lf
.lfCharSet
) {
2930 case DEFAULT_CHARSET
:
2931 csi
.fs
.fsCsb
[0] = 0;
2934 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
2935 csi
.fs
.fsCsb
[0] = 0;
2941 if(lf
.lfFaceName
[0] != '\0') {
2943 SYSTEM_LINKS
*font_link
;
2944 CHILD_FONT
*font_link_entry
;
2946 psub
= get_font_subst(&font_subst_list
, lf
.lfFaceName
, lf
.lfCharSet
);
2949 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
2950 debugstr_w(psub
->to
.name
));
2951 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2954 /* We want a match on name and charset or just name if
2955 charset was DEFAULT_CHARSET. If the latter then
2956 we fixup the returned charset later in get_nearest_charset
2957 where we'll either use the charset of the current ansi codepage
2958 or if that's unavailable the first charset that the font supports.
2960 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2961 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2962 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2963 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2964 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2965 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2966 if(face
->scalable
|| can_use_bitmap
)
2973 * Try check the SystemLink list first for a replacement font.
2974 * We may find good replacements there.
2976 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2978 if(!strcmpiW(font_link
->font_name
, lf
.lfFaceName
))
2980 TRACE("found entry in system list\n");
2981 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2983 face
= font_link_entry
->face
;
2984 family
= face
->family
;
2985 if(csi
.fs
.fsCsb
[0] &
2986 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
2988 if(face
->scalable
|| can_use_bitmap
)
2996 /* If requested charset was DEFAULT_CHARSET then try using charset
2997 corresponding to the current ansi codepage */
2998 if(!csi
.fs
.fsCsb
[0]) {
3000 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3001 FIXME("TCI failed on codepage %d\n", acp
);
3002 csi
.fs
.fsCsb
[0] = 0;
3004 lf
.lfCharSet
= csi
.ciCharset
;
3007 /* Face families are in the top 4 bits of lfPitchAndFamily,
3008 so mask with 0xF0 before testing */
3010 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3011 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3012 strcpyW(lf
.lfFaceName
, defFixed
);
3013 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3014 strcpyW(lf
.lfFaceName
, defSerif
);
3015 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3016 strcpyW(lf
.lfFaceName
, defSans
);
3018 strcpyW(lf
.lfFaceName
, defSans
);
3019 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3020 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3021 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3022 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3023 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3024 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3025 if(face
->scalable
|| can_use_bitmap
)
3031 last_resort_family
= NULL
;
3032 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3033 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3034 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3035 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3036 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3039 if(can_use_bitmap
&& !last_resort_family
)
3040 last_resort_family
= family
;
3045 if(last_resort_family
) {
3046 family
= last_resort_family
;
3047 csi
.fs
.fsCsb
[0] = 0;
3051 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3052 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3053 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3054 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3055 if(face
->scalable
) {
3056 csi
.fs
.fsCsb
[0] = 0;
3057 WARN("just using first face for now\n");
3060 if(can_use_bitmap
&& !last_resort_family
)
3061 last_resort_family
= family
;
3064 if(!last_resort_family
) {
3065 FIXME("can't find a single appropriate font - bailing\n");
3070 WARN("could only find a bitmap font - this will probably look awful!\n");
3071 family
= last_resort_family
;
3072 csi
.fs
.fsCsb
[0] = 0;
3075 it
= lf
.lfItalic
? 1 : 0;
3076 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3078 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
3079 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
3081 face
= best
= best_bitmap
= NULL
;
3082 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3084 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3086 new_score
= (face
->Italic
^ it
) + (face
->Bold
^ bd
);
3087 if(!best
|| new_score
<= score
)
3089 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3090 face
->Italic
, face
->Bold
, it
, bd
);
3093 if(best
->scalable
&& score
== 0) break;
3097 newdiff
= height
- (signed int)(best
->size
.height
);
3099 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3100 if(!best_bitmap
|| new_score
< score
||
3101 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3103 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3106 if(score
== 0 && diff
== 0) break;
3113 face
= best
->scalable
? best
: best_bitmap
;
3114 ret
->fake_italic
= (it
&& !face
->Italic
);
3115 ret
->fake_bold
= (bd
&& !face
->Bold
);
3117 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
3119 if(csi
.fs
.fsCsb
[0]) {
3120 ret
->charset
= lf
.lfCharSet
;
3121 ret
->codepage
= csi
.ciACP
;
3124 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3126 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3127 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3129 if(!face
->scalable
) {
3130 width
= face
->size
.x_ppem
>> 6;
3131 height
= face
->size
.y_ppem
>> 6;
3133 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3141 ret
->ntmFlags
= face
->ntmFlags
;
3143 if (ret
->charset
== SYMBOL_CHARSET
&&
3144 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3147 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3151 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3154 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3155 ret
->name
= strdupW(family
->FamilyName
);
3156 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3157 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3158 create_child_font_list(ret
);
3160 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3162 ret
->aveWidth
= FT_IS_SCALABLE(ret
->ft_face
) ? abs(lf
.lfWidth
) : 0;
3163 list_add_head(&gdi_font_list
, &ret
->entry
);
3167 static void dump_gdi_font_list(void)
3170 struct list
*elem_ptr
;
3172 TRACE("---------- gdiFont Cache ----------\n");
3173 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3174 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3175 TRACE("gdiFont=%p %s %d\n",
3176 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3179 TRACE("---------- Unused gdiFont Cache ----------\n");
3180 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3181 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3182 TRACE("gdiFont=%p %s %d\n",
3183 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3187 /*************************************************************
3188 * WineEngDestroyFontInstance
3190 * free the gdiFont associated with this handle
3193 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3198 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3201 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3203 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3204 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3205 if(hflist
->hfont
== handle
)
3207 TRACE("removing child font %p from child list\n", gdiFont
);
3208 list_remove(&gdiFont
->entry
);
3213 TRACE("destroying hfont=%p\n", handle
);
3215 dump_gdi_font_list();
3217 font_elem_ptr
= list_head(&gdi_font_list
);
3218 while(font_elem_ptr
) {
3219 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3220 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3222 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3223 while(hfontlist_elem_ptr
) {
3224 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3225 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3226 if(hflist
->hfont
== handle
) {
3227 list_remove(&hflist
->entry
);
3228 HeapFree(GetProcessHeap(), 0, hflist
);
3232 if(list_empty(&gdiFont
->hfontlist
)) {
3233 TRACE("Moving to Unused list\n");
3234 list_remove(&gdiFont
->entry
);
3235 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3240 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3241 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3242 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3243 while(font_elem_ptr
) {
3244 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3245 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3246 TRACE("freeing %p\n", gdiFont
);
3247 list_remove(&gdiFont
->entry
);
3253 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3254 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3256 OUTLINETEXTMETRICW
*potm
= NULL
;
3258 TEXTMETRICW tm
, *ptm
;
3259 GdiFont
*font
= alloc_font();
3262 if (face
->cache_valid
)
3265 memcpy(pelf
,&face
->elf
,sizeof(ENUMLOGFONTEXW
));
3266 memcpy(pntm
,&face
->ntm
,sizeof(NEWTEXTMETRICEXW
));
3267 *ptype
= face
->type
;
3271 if(face
->scalable
) {
3275 height
= face
->size
.y_ppem
>> 6;
3276 width
= face
->size
.x_ppem
>> 6;
3279 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3285 font
->name
= strdupW(face
->family
->FamilyName
);
3286 font
->ntmFlags
= face
->ntmFlags
;
3288 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
3290 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
3292 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3293 WineEngGetOutlineTextMetrics(font
, size
, potm
);
3294 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
3296 WineEngGetTextMetrics(font
, &tm
);
3300 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
3301 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
3302 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
3303 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
3304 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
3305 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
3306 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
3307 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
3308 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
3309 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
3310 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
3311 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
3312 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
3313 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
3314 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
3315 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
3316 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
3317 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
3318 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
3319 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
3320 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
3321 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3322 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3323 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3326 if (ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
)
3327 *ptype
|= TRUETYPE_FONTTYPE
;
3328 if (ptm
->tmPitchAndFamily
& TMPF_DEVICE
)
3329 *ptype
|= DEVICE_FONTTYPE
;
3330 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
3331 *ptype
|= RASTER_FONTTYPE
;
3333 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
3334 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
3335 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
3336 pntm
->ntmTm
.ntmFlags
|= face
->ntmFlags
;
3338 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3339 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3340 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
3343 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
3345 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3346 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
3348 lstrcpynW(pelf
->elfFullName
,
3349 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
3351 lstrcpynW(pelf
->elfStyle
,
3352 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
3355 HeapFree(GetProcessHeap(), 0, potm
);
3357 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3359 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3360 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
3361 pelf
->elfStyle
[0] = '\0';
3364 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3366 memcpy(&face
->elf
,pelf
,sizeof(ENUMLOGFONTEXW
));
3367 memcpy(&face
->ntm
,pntm
,sizeof(NEWTEXTMETRICEXW
));
3368 face
->type
= *ptype
;
3369 face
->cache_valid
= TRUE
;
3374 /*************************************************************
3378 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3382 struct list
*family_elem_ptr
, *face_elem_ptr
;
3384 NEWTEXTMETRICEXW ntm
;
3385 DWORD type
, ret
= 1;
3391 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3393 if(plf
->lfFaceName
[0]) {
3395 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3398 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3399 debugstr_w(psub
->to
.name
));
3400 memcpy(&lf
, plf
, sizeof(lf
));
3401 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3405 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3406 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3407 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3408 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3409 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3410 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3411 for(i
= 0; i
< 32; i
++) {
3412 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3413 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3414 strcpyW(elf
.elfScript
, OEM_DOSW
);
3415 i
= 32; /* break out of loop */
3416 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3419 fs
.fsCsb
[0] = 1L << i
;
3421 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3423 csi
.ciCharset
= DEFAULT_CHARSET
;
3424 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3425 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3426 elf
.elfLogFont
.lfCharSet
=
3427 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3429 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3431 FIXME("Unknown elfscript for bit %d\n", i
);
3434 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3435 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3436 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3437 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3438 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3439 ntm
.ntmTm
.ntmFlags
);
3440 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3447 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3448 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3449 face_elem_ptr
= list_head(&family
->faces
);
3450 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3451 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3452 for(i
= 0; i
< 32; i
++) {
3453 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3454 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3455 strcpyW(elf
.elfScript
, OEM_DOSW
);
3456 i
= 32; /* break out of loop */
3457 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3460 fs
.fsCsb
[0] = 1L << i
;
3462 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3464 csi
.ciCharset
= DEFAULT_CHARSET
;
3465 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3466 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3467 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3470 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3472 FIXME("Unknown elfscript for bit %d\n", i
);
3475 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3476 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3477 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3478 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3479 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3480 ntm
.ntmTm
.ntmFlags
);
3481 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3490 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3492 pt
->x
.value
= vec
->x
>> 6;
3493 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3494 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3495 pt
->y
.value
= vec
->y
>> 6;
3496 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3497 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3501 /***************************************************
3502 * According to the MSDN documentation on WideCharToMultiByte,
3503 * certain codepages cannot set the default_used parameter.
3504 * This returns TRUE if the codepage can set that parameter, false else
3505 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3507 static BOOL
codepage_sets_default_used(UINT codepage
)
3520 static FT_UInt
get_glyph_index(GdiFont
*font
, UINT glyph
)
3522 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
3523 WCHAR wc
= (WCHAR
)glyph
;
3525 BOOL
*default_used_pointer
;
3528 default_used_pointer
= NULL
;
3529 default_used
= FALSE
;
3530 if (codepage_sets_default_used(font
->codepage
))
3531 default_used_pointer
= &default_used
;
3532 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
3535 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
3536 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
3540 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
3541 glyph
= glyph
+ 0xf000;
3542 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
3545 /*************************************************************
3546 * WineEngGetGlyphIndices
3548 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3550 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
3551 LPWORD pgi
, DWORD flags
)
3554 WCHAR default_char
= 0;
3557 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0x001f; /* Indicate non existence */
3559 for(i
= 0; i
< count
; i
++)
3561 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
3566 WineEngGetTextMetrics(font
, &textm
);
3567 default_char
= textm
.tmDefaultChar
;
3569 pgi
[i
] = default_char
;
3575 /*************************************************************
3576 * WineEngGetGlyphOutline
3578 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3579 * except that the first parameter is the HWINEENGFONT of the font in
3580 * question rather than an HDC.
3583 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
3584 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3587 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
3588 FT_Face ft_face
= incoming_font
->ft_face
;
3589 GdiFont
*font
= incoming_font
;
3590 FT_UInt glyph_index
;
3591 DWORD width
, height
, pitch
, needed
= 0;
3592 FT_Bitmap ft_bitmap
;
3594 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
3596 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3597 float widthRatio
= 1.0;
3598 FT_Matrix transMat
= identityMat
;
3599 BOOL needsTransform
= FALSE
;
3602 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
3603 buflen
, buf
, lpmat
);
3605 if(format
& GGO_GLYPH_INDEX
) {
3606 glyph_index
= glyph
;
3607 format
&= ~GGO_GLYPH_INDEX
;
3609 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
3610 ft_face
= font
->ft_face
;
3613 if(glyph_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
3614 font
->gmsize
= (glyph_index
/ GM_BLOCK_SIZE
+ 1);
3615 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
3616 font
->gmsize
* sizeof(GM
*));
3618 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] != NULL
&& FONT_GM(font
,glyph_index
)->init
) {
3619 *lpgm
= FONT_GM(font
,glyph_index
)->gm
;
3620 return 1; /* FIXME */
3624 if (!font
->gm
[glyph_index
/ GM_BLOCK_SIZE
])
3625 font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3627 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) || font
->aveWidth
|| lpmat
)
3628 load_flags
|= FT_LOAD_NO_BITMAP
;
3630 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
3633 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
3637 /* Scaling factor */
3638 if (font
->aveWidth
&& font
->potm
) {
3639 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
3642 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
3643 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
3645 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
3647 bbx
= (right
- left
) >> 6;
3649 /* Scaling transform */
3650 if(font
->aveWidth
) {
3652 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
3655 scaleMat
.yy
= (1 << 16);
3657 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
3658 needsTransform
= TRUE
;
3661 /* Slant transform */
3662 if (font
->fake_italic
) {
3665 slantMat
.xx
= (1 << 16);
3666 slantMat
.xy
= ((1 << 16) >> 2);
3668 slantMat
.yy
= (1 << 16);
3669 pFT_Matrix_Multiply(&slantMat
, &transMat
);
3670 needsTransform
= TRUE
;
3673 /* Rotation transform */
3674 if(font
->orientation
) {
3675 FT_Matrix rotationMat
;
3677 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
3678 pFT_Vector_Unit(&vecAngle
, angle
);
3679 rotationMat
.xx
= vecAngle
.x
;
3680 rotationMat
.xy
= -vecAngle
.y
;
3681 rotationMat
.yx
= -rotationMat
.xy
;
3682 rotationMat
.yy
= rotationMat
.xx
;
3684 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
3685 needsTransform
= TRUE
;
3688 /* Extra transformation specified by caller */
3691 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
3692 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
3693 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
3694 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
3695 pFT_Matrix_Multiply(&extraMat
, &transMat
);
3696 needsTransform
= TRUE
;
3699 if(!needsTransform
) {
3700 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
3701 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
3702 ft_face
->glyph
->metrics
.height
) & -64;
3703 lpgm
->gmCellIncX
= adv
;
3704 lpgm
->gmCellIncY
= 0;
3708 for(xc
= 0; xc
< 2; xc
++) {
3709 for(yc
= 0; yc
< 2; yc
++) {
3710 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
3711 xc
* ft_face
->glyph
->metrics
.width
);
3712 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
3713 yc
* ft_face
->glyph
->metrics
.height
;
3714 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
3715 pFT_Vector_Transform(&vec
, &transMat
);
3716 if(xc
== 0 && yc
== 0) {
3717 left
= right
= vec
.x
;
3718 top
= bottom
= vec
.y
;
3720 if(vec
.x
< left
) left
= vec
.x
;
3721 else if(vec
.x
> right
) right
= vec
.x
;
3722 if(vec
.y
< bottom
) bottom
= vec
.y
;
3723 else if(vec
.y
> top
) top
= vec
.y
;
3728 right
= (right
+ 63) & -64;
3729 bottom
= bottom
& -64;
3730 top
= (top
+ 63) & -64;
3732 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
3733 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
3735 pFT_Vector_Transform(&vec
, &transMat
);
3736 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
3737 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
3739 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
3740 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
3741 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
3742 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
3744 if(format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
)
3746 FONT_GM(font
,glyph_index
)->gm
= *lpgm
;
3747 FONT_GM(font
,glyph_index
)->adv
= adv
;
3748 FONT_GM(font
,glyph_index
)->lsb
= lsb
;
3749 FONT_GM(font
,glyph_index
)->bbx
= bbx
;
3750 FONT_GM(font
,glyph_index
)->init
= TRUE
;
3753 if(format
== GGO_METRICS
)
3754 return 1; /* FIXME */
3756 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) {
3757 TRACE("loaded a bitmap\n");
3763 width
= lpgm
->gmBlackBoxX
;
3764 height
= lpgm
->gmBlackBoxY
;
3765 pitch
= ((width
+ 31) >> 5) << 2;
3766 needed
= pitch
* height
;
3768 if(!buf
|| !buflen
) break;
3770 switch(ft_face
->glyph
->format
) {
3771 case ft_glyph_format_bitmap
:
3773 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3774 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
3775 INT h
= ft_face
->glyph
->bitmap
.rows
;
3777 memcpy(dst
, src
, w
);
3778 src
+= ft_face
->glyph
->bitmap
.pitch
;
3784 case ft_glyph_format_outline
:
3785 ft_bitmap
.width
= width
;
3786 ft_bitmap
.rows
= height
;
3787 ft_bitmap
.pitch
= pitch
;
3788 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
3789 ft_bitmap
.buffer
= buf
;
3791 if(needsTransform
) {
3792 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3795 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3797 /* Note: FreeType will only set 'black' bits for us. */
3798 memset(buf
, 0, needed
);
3799 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3803 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3808 case GGO_GRAY2_BITMAP
:
3809 case GGO_GRAY4_BITMAP
:
3810 case GGO_GRAY8_BITMAP
:
3811 case WINE_GGO_GRAY16_BITMAP
:
3813 unsigned int mult
, row
, col
;
3816 width
= lpgm
->gmBlackBoxX
;
3817 height
= lpgm
->gmBlackBoxY
;
3818 pitch
= (width
+ 3) / 4 * 4;
3819 needed
= pitch
* height
;
3821 if(!buf
|| !buflen
) break;
3823 switch(ft_face
->glyph
->format
) {
3824 case ft_glyph_format_bitmap
:
3826 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3827 INT h
= ft_face
->glyph
->bitmap
.rows
;
3830 for(x
= 0; x
< pitch
; x
++)
3831 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
3832 src
+= ft_face
->glyph
->bitmap
.pitch
;
3837 case ft_glyph_format_outline
:
3839 ft_bitmap
.width
= width
;
3840 ft_bitmap
.rows
= height
;
3841 ft_bitmap
.pitch
= pitch
;
3842 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
3843 ft_bitmap
.buffer
= buf
;
3846 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3848 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3850 memset(ft_bitmap
.buffer
, 0, buflen
);
3852 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3854 if(format
== GGO_GRAY2_BITMAP
)
3856 else if(format
== GGO_GRAY4_BITMAP
)
3858 else if(format
== GGO_GRAY8_BITMAP
)
3860 else /* format == WINE_GGO_GRAY16_BITMAP */
3866 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3871 for(row
= 0; row
< height
; row
++) {
3873 for(col
= 0; col
< width
; col
++, ptr
++) {
3874 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
3883 int contour
, point
= 0, first_pt
;
3884 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3885 TTPOLYGONHEADER
*pph
;
3887 DWORD pph_start
, cpfx
, type
;
3889 if(buflen
== 0) buf
= NULL
;
3891 if (needsTransform
&& buf
) {
3892 pFT_Outline_Transform(outline
, &transMat
);
3895 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3897 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3900 pph
->dwType
= TT_POLYGON_TYPE
;
3901 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3903 needed
+= sizeof(*pph
);
3905 while(point
<= outline
->contours
[contour
]) {
3906 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3907 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3908 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3912 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3915 } while(point
<= outline
->contours
[contour
] &&
3916 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3917 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3918 /* At the end of a contour Windows adds the start point, but
3920 if(point
> outline
->contours
[contour
] &&
3921 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3923 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3925 } else if(point
<= outline
->contours
[contour
] &&
3926 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3927 /* add closing pt for bezier */
3929 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3937 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3940 pph
->cb
= needed
- pph_start
;
3946 /* Convert the quadratic Beziers to cubic Beziers.
3947 The parametric eqn for a cubic Bezier is, from PLRM:
3948 r(t) = at^3 + bt^2 + ct + r0
3949 with the control points:
3954 A quadratic Beizer has the form:
3955 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3957 So equating powers of t leads to:
3958 r1 = 2/3 p1 + 1/3 p0
3959 r2 = 2/3 p1 + 1/3 p2
3960 and of course r0 = p0, r3 = p2
3963 int contour
, point
= 0, first_pt
;
3964 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3965 TTPOLYGONHEADER
*pph
;
3967 DWORD pph_start
, cpfx
, type
;
3968 FT_Vector cubic_control
[4];
3969 if(buflen
== 0) buf
= NULL
;
3971 if (needsTransform
&& buf
) {
3972 pFT_Outline_Transform(outline
, &transMat
);
3975 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3977 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3980 pph
->dwType
= TT_POLYGON_TYPE
;
3981 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3983 needed
+= sizeof(*pph
);
3985 while(point
<= outline
->contours
[contour
]) {
3986 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3987 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3988 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3991 if(type
== TT_PRIM_LINE
) {
3993 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3997 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4000 /* FIXME: Possible optimization in endpoint calculation
4001 if there are two consecutive curves */
4002 cubic_control
[0] = outline
->points
[point
-1];
4003 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4004 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
4005 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
4006 cubic_control
[0].x
>>= 1;
4007 cubic_control
[0].y
>>= 1;
4009 if(point
+1 > outline
->contours
[contour
])
4010 cubic_control
[3] = outline
->points
[first_pt
];
4012 cubic_control
[3] = outline
->points
[point
+1];
4013 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
4014 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
4015 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
4016 cubic_control
[3].x
>>= 1;
4017 cubic_control
[3].y
>>= 1;
4020 /* r1 = 1/3 p0 + 2/3 p1
4021 r2 = 1/3 p2 + 2/3 p1 */
4022 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
4023 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
4024 cubic_control
[2] = cubic_control
[1];
4025 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
4026 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
4027 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
4028 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
4030 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
4031 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
4032 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
4037 } while(point
<= outline
->contours
[contour
] &&
4038 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4039 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4040 /* At the end of a contour Windows adds the start point,
4041 but only for Beziers and we've already done that.
4043 if(point
<= outline
->contours
[contour
] &&
4044 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4045 /* This is the closing pt of a bezier, but we've already
4046 added it, so just inc point and carry on */
4053 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4056 pph
->cb
= needed
- pph_start
;
4062 FIXME("Unsupported format %d\n", format
);
4068 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
4070 FT_Face ft_face
= font
->ft_face
;
4071 #ifdef HAVE_FREETYPE_FTWINFNT_H
4072 FT_WinFNT_HeaderRec winfnt_header
;
4074 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
4075 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
4076 font
->potm
->otmSize
= size
;
4078 #define TM font->potm->otmTextMetrics
4079 #ifdef HAVE_FREETYPE_FTWINFNT_H
4080 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
4082 TM
.tmHeight
= winfnt_header
.pixel_height
;
4083 TM
.tmAscent
= winfnt_header
.ascent
;
4084 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
4085 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
4086 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
4087 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
4088 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4089 TM
.tmWeight
= winfnt_header
.weight
;
4091 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4092 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4093 TM
.tmFirstChar
= winfnt_header
.first_char
;
4094 TM
.tmLastChar
= winfnt_header
.last_char
;
4095 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4096 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4097 TM
.tmItalic
= winfnt_header
.italic
;
4098 TM
.tmUnderlined
= font
->underline
;
4099 TM
.tmStruckOut
= font
->strikeout
;
4100 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4101 TM
.tmCharSet
= winfnt_header
.charset
;
4106 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4107 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4108 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4109 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4110 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4111 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4112 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4113 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4115 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4116 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4118 TM
.tmLastChar
= 255;
4119 TM
.tmDefaultChar
= 32;
4120 TM
.tmBreakChar
= 32;
4121 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4122 TM
.tmUnderlined
= font
->underline
;
4123 TM
.tmStruckOut
= font
->strikeout
;
4124 /* NB inverted meaning of TMPF_FIXED_PITCH */
4125 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4126 TM
.tmCharSet
= font
->charset
;
4133 /*************************************************************
4134 * WineEngGetTextMetrics
4137 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4140 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4141 if(!get_bitmap_text_metrics(font
))
4144 if(!font
->potm
) return FALSE
;
4145 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
4147 if (font
->aveWidth
) {
4148 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4154 /*************************************************************
4155 * WineEngGetOutlineTextMetrics
4158 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4159 OUTLINETEXTMETRICW
*potm
)
4161 FT_Face ft_face
= font
->ft_face
;
4162 UINT needed
, lenfam
, lensty
, ret
;
4164 TT_HoriHeader
*pHori
;
4165 TT_Postscript
*pPost
;
4166 FT_Fixed x_scale
, y_scale
;
4167 WCHAR
*family_nameW
, *style_nameW
;
4168 static const WCHAR spaceW
[] = {' ', '\0'};
4170 INT ascent
, descent
;
4172 TRACE("font=%p\n", font
);
4174 if(!FT_IS_SCALABLE(ft_face
))
4178 if(cbSize
>= font
->potm
->otmSize
)
4179 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4180 return font
->potm
->otmSize
;
4184 needed
= sizeof(*potm
);
4186 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
4187 family_nameW
= strdupW(font
->name
);
4189 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
4191 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
4192 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
4193 style_nameW
, lensty
/sizeof(WCHAR
));
4195 /* These names should be read from the TT name table */
4197 /* length of otmpFamilyName */
4200 /* length of otmpFaceName */
4201 if(!strcasecmp(ft_face
->style_name
, "regular")) {
4202 needed
+= lenfam
; /* just the family name */
4204 needed
+= lenfam
+ lensty
; /* family + " " + style */
4207 /* length of otmpStyleName */
4210 /* length of otmpFullName */
4211 needed
+= lenfam
+ lensty
;
4214 x_scale
= ft_face
->size
->metrics
.x_scale
;
4215 y_scale
= ft_face
->size
->metrics
.y_scale
;
4217 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4219 FIXME("Can't find OS/2 table - not TT font?\n");
4224 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4226 FIXME("Can't find HHEA table - not TT font?\n");
4231 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
4233 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",
4234 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
4235 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
4236 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
4237 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
4238 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
4240 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
4241 font
->potm
->otmSize
= needed
;
4243 #define TM font->potm->otmTextMetrics
4245 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
4246 ascent
= pHori
->Ascender
;
4247 descent
= -pHori
->Descender
;
4249 ascent
= pOS2
->usWinAscent
;
4250 descent
= pOS2
->usWinDescent
;
4254 TM
.tmAscent
= font
->yMax
;
4255 TM
.tmDescent
= -font
->yMin
;
4256 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4258 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4259 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4260 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4261 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4264 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4267 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4269 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4270 ((ascent
+ descent
) -
4271 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4273 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4274 if (TM
.tmAveCharWidth
== 0) {
4275 TM
.tmAveCharWidth
= 1;
4277 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4278 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4280 TM
.tmDigitizedAspectX
= 300;
4281 TM
.tmDigitizedAspectY
= 300;
4282 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4283 * symbol range to 0 - f0ff
4285 if (font
->charset
== SYMBOL_CHARSET
)
4288 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4289 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4290 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4291 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4292 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4293 TM
.tmUnderlined
= font
->underline
;
4294 TM
.tmStruckOut
= font
->strikeout
;
4296 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4297 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4298 (pOS2
->version
== 0xFFFFU
||
4299 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4300 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4302 TM
.tmPitchAndFamily
= 0;
4304 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4305 case PAN_FAMILY_SCRIPT
:
4306 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4308 case PAN_FAMILY_DECORATIVE
:
4309 case PAN_FAMILY_PICTORIAL
:
4310 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4312 case PAN_FAMILY_TEXT_DISPLAY
:
4313 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4314 TM
.tmPitchAndFamily
= FF_MODERN
;
4316 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4317 case PAN_SERIF_NORMAL_SANS
:
4318 case PAN_SERIF_OBTUSE_SANS
:
4319 case PAN_SERIF_PERP_SANS
:
4320 TM
.tmPitchAndFamily
|= FF_SWISS
;
4323 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4328 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4331 if(FT_IS_SCALABLE(ft_face
))
4332 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4334 if(FT_IS_SFNT(ft_face
))
4336 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
4337 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
4339 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4342 TM
.tmCharSet
= font
->charset
;
4345 font
->potm
->otmFiller
= 0;
4346 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4347 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4348 font
->potm
->otmfsType
= pOS2
->fsType
;
4349 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4350 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4351 font
->potm
->otmItalicAngle
= 0; /* POST table */
4352 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4353 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4354 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4355 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4356 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4357 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
4358 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4359 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
4360 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
4361 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
4362 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
4363 font
->potm
->otmMacDescent
= 0;
4364 font
->potm
->otmMacLineGap
= 0;
4365 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
4366 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
4367 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
4368 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
4369 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
4370 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
4371 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
4372 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
4373 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
4374 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
4375 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
4377 font
->potm
->otmsUnderscoreSize
= 0;
4378 font
->potm
->otmsUnderscorePosition
= 0;
4380 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
4381 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
4384 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4385 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
4386 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
4387 strcpyW((WCHAR
*)cp
, family_nameW
);
4389 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
4390 strcpyW((WCHAR
*)cp
, style_nameW
);
4392 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
4393 strcpyW((WCHAR
*)cp
, family_nameW
);
4394 if(strcasecmp(ft_face
->style_name
, "regular")) {
4395 strcatW((WCHAR
*)cp
, spaceW
);
4396 strcatW((WCHAR
*)cp
, style_nameW
);
4397 cp
+= lenfam
+ lensty
;
4400 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
4401 strcpyW((WCHAR
*)cp
, family_nameW
);
4402 strcatW((WCHAR
*)cp
, spaceW
);
4403 strcatW((WCHAR
*)cp
, style_nameW
);
4406 if(potm
&& needed
<= cbSize
)
4407 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4410 HeapFree(GetProcessHeap(), 0, style_nameW
);
4411 HeapFree(GetProcessHeap(), 0, family_nameW
);
4416 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
4418 HFONTLIST
*hfontlist
;
4419 child
->font
= alloc_font();
4420 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
4421 if(!child
->font
->ft_face
)
4423 free_font(child
->font
);
4428 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
4429 child
->font
->orientation
= font
->orientation
;
4430 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
4431 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
4432 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
4433 child
->font
->base_font
= font
;
4434 list_add_head(&child_font_list
, &child
->font
->entry
);
4435 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
4439 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
4442 CHILD_FONT
*child_font
;
4445 font
= font
->base_font
;
4447 *linked_font
= font
;
4449 if((*glyph
= get_glyph_index(font
, c
)))
4452 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
4454 if(!child_font
->font
)
4455 if(!load_child_font(font
, child_font
))
4458 if(!child_font
->font
->ft_face
)
4460 g
= get_glyph_index(child_font
->font
, c
);
4464 *linked_font
= child_font
->font
;
4471 /*************************************************************
4472 * WineEngGetCharWidth
4475 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4480 FT_UInt glyph_index
;
4481 GdiFont
*linked_font
;
4483 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4485 for(c
= firstChar
; c
<= lastChar
; c
++) {
4486 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4487 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4488 &gm
, 0, NULL
, NULL
);
4489 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
4494 /*************************************************************
4495 * WineEngGetCharABCWidths
4498 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4503 FT_UInt glyph_index
;
4504 GdiFont
*linked_font
;
4506 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4508 if(!FT_IS_SCALABLE(font
->ft_face
))
4511 for(c
= firstChar
; c
<= lastChar
; c
++) {
4512 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4513 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4514 &gm
, 0, NULL
, NULL
);
4515 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
4516 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
4517 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
4518 FONT_GM(linked_font
,glyph_index
)->bbx
;
4523 /*************************************************************
4524 * WineEngGetCharABCWidthsI
4527 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4532 FT_UInt glyph_index
;
4533 GdiFont
*linked_font
;
4535 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
4538 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
4540 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
4541 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4542 &gm
, 0, NULL
, NULL
);
4543 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
4544 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
4545 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
4546 - FONT_GM(linked_font
,c
)->bbx
;
4549 for(c
= 0; c
< count
; c
++) {
4550 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4551 &gm
, 0, NULL
, NULL
);
4552 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
4553 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
4554 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
4555 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
4561 /*************************************************************
4562 * WineEngGetTextExtentExPoint
4565 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4566 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4572 FT_UInt glyph_index
;
4573 GdiFont
*linked_font
;
4575 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
4579 WineEngGetTextMetrics(font
, &tm
);
4580 size
->cy
= tm
.tmHeight
;
4582 for(idx
= 0; idx
< count
; idx
++) {
4583 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
4584 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4585 &gm
, 0, NULL
, NULL
);
4586 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
4588 if (! pnfit
|| ext
<= max_ext
) {
4598 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4602 /*************************************************************
4603 * WineEngGetTextExtentExPointI
4606 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4607 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4614 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
4617 WineEngGetTextMetrics(font
, &tm
);
4618 size
->cy
= tm
.tmHeight
;
4620 for(idx
= 0; idx
< count
; idx
++) {
4621 WineEngGetGlyphOutline(font
, indices
[idx
],
4622 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
4624 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
4626 if (! pnfit
|| ext
<= max_ext
) {
4636 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4640 /*************************************************************
4641 * WineEngGetFontData
4644 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4647 FT_Face ft_face
= font
->ft_face
;
4651 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4652 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
4653 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
4655 if(!FT_IS_SFNT(ft_face
))
4663 if(table
) { /* MS tags differ in endidness from FT ones */
4664 table
= table
>> 24 | table
<< 24 |
4665 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
4668 /* make sure value of len is the value freetype says it needs */
4671 FT_ULong needed
= 0;
4672 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
4673 if( !err
&& needed
< len
) len
= needed
;
4675 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
4678 TRACE("Can't find table %c%c%c%c\n",
4679 /* bytes were reversed */
4680 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4681 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4687 /*************************************************************
4688 * WineEngGetTextFace
4691 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4694 lstrcpynW(str
, font
->name
, count
);
4695 return strlenW(font
->name
);
4697 return strlenW(font
->name
) + 1;
4700 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4702 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
4703 return font
->charset
;
4706 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4708 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
4709 struct list
*first_hfont
;
4712 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
4713 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
4714 if(font
== linked_font
)
4715 *new_hfont
= dc
->hFont
;
4718 first_hfont
= list_head(&linked_font
->hfontlist
);
4719 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
4725 /* Retrieve a list of supported Unicode ranges for a given font.
4726 * Can be called with NULL gs to calculate the buffer size. Returns
4727 * the number of ranges found.
4729 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
4731 DWORD num_ranges
= 0;
4733 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4736 FT_ULong char_code
, char_code_prev
;
4739 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
4741 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4742 face
->num_glyphs
, glyph_code
, char_code
);
4744 if (!glyph_code
) return 0;
4748 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4749 gs
->ranges
[0].cGlyphs
= 0;
4750 gs
->cGlyphsSupported
= 0;
4756 if (char_code
< char_code_prev
)
4758 ERR("expected increasing char code from FT_Get_Next_Char\n");
4761 if (char_code
- char_code_prev
> 1)
4766 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4767 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4768 gs
->cGlyphsSupported
++;
4773 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4774 gs
->cGlyphsSupported
++;
4776 char_code_prev
= char_code
;
4777 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
4781 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
4786 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
4789 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
4791 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
4794 glyphset
->cbThis
= size
;
4795 glyphset
->cRanges
= num_ranges
;
4800 /*************************************************************
4803 BOOL
WineEngFontIsLinked(GdiFont
*font
)
4805 return !list_empty(&font
->child_fonts
);
4808 static BOOL
is_hinting_enabled(void)
4810 /* Use the >= 2.2.0 function if available */
4811 if(pFT_Get_TrueType_Engine_Type
)
4813 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
4814 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
4816 #ifdef FT_DRIVER_HAS_HINTER
4821 /* otherwise if we've been compiled with < 2.2.0 headers
4822 use the internal macro */
4823 mod
= pFT_Get_Module(library
, "truetype");
4824 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
4832 /*************************************************************************
4833 * GetRasterizerCaps (GDI32.@)
4835 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
4837 static int hinting
= -1;
4841 hinting
= is_hinting_enabled();
4842 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
4845 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
4846 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
4847 lprs
->nLanguageID
= 0;
4851 /*************************************************************************
4852 * Kerning support for TrueType fonts
4854 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4856 struct TT_kern_table
4862 struct TT_kern_subtable
4871 USHORT horizontal
: 1;
4873 USHORT cross_stream
: 1;
4874 USHORT override
: 1;
4875 USHORT reserved1
: 4;
4881 struct TT_format0_kern_subtable
4885 USHORT entrySelector
;
4896 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
4897 const struct TT_format0_kern_subtable
*tt_f0_ks
,
4898 const USHORT
*glyph_to_char
,
4899 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
4902 const struct TT_kern_pair
*tt_kern_pair
;
4904 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
4906 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
4908 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4909 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
4910 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
4912 if (!kern_pair
|| !cPairs
)
4915 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
4917 nPairs
= min(nPairs
, cPairs
);
4919 for (i
= 0; i
< nPairs
; i
++)
4921 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
4922 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
4923 /* this algorithm appears to better match what Windows does */
4924 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
4925 if (kern_pair
->iKernAmount
< 0)
4927 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
4928 kern_pair
->iKernAmount
-= font
->ppem
;
4930 else if (kern_pair
->iKernAmount
> 0)
4932 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
4933 kern_pair
->iKernAmount
+= font
->ppem
;
4935 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
4937 TRACE("left %u right %u value %d\n",
4938 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
4942 TRACE("copied %u entries\n", nPairs
);
4946 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
4950 const struct TT_kern_table
*tt_kern_table
;
4951 const struct TT_kern_subtable
*tt_kern_subtable
;
4953 USHORT
*glyph_to_char
;
4955 if (font
->total_kern_pairs
!= (DWORD
)-1)
4957 if (cPairs
&& kern_pair
)
4959 cPairs
= min(cPairs
, font
->total_kern_pairs
);
4960 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
4963 return font
->total_kern_pairs
;
4966 font
->total_kern_pairs
= 0;
4968 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
4970 if (length
== GDI_ERROR
)
4972 TRACE("no kerning data in the font\n");
4976 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
4979 WARN("Out of memory\n");
4983 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
4985 /* build a glyph index to char code map */
4986 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
4989 WARN("Out of memory allocating a glyph index to char code map\n");
4990 HeapFree(GetProcessHeap(), 0, buf
);
4994 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5000 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
5002 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5003 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
5007 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5009 /* FIXME: This doesn't match what Windows does: it does some fancy
5010 * things with duplicate glyph index to char code mappings, while
5011 * we just avoid overriding existing entries.
5013 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
5014 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
5016 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
5023 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
5024 for (n
= 0; n
<= 65535; n
++)
5025 glyph_to_char
[n
] = (USHORT
)n
;
5028 tt_kern_table
= buf
;
5029 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
5030 TRACE("version %u, nTables %u\n",
5031 GET_BE_WORD(tt_kern_table
->version
), nTables
);
5033 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
5035 for (i
= 0; i
< nTables
; i
++)
5037 struct TT_kern_subtable tt_kern_subtable_copy
;
5039 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
5040 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
5041 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
5043 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5044 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
5045 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
5047 /* According to the TrueType specification this is the only format
5048 * that will be properly interpreted by Windows and OS/2
5050 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
5052 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
5054 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5055 glyph_to_char
, NULL
, 0);
5056 font
->total_kern_pairs
+= new_chunk
;
5058 if (!font
->kern_pairs
)
5059 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
5060 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5062 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
5063 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5065 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5066 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
5069 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
5071 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
5074 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
5075 HeapFree(GetProcessHeap(), 0, buf
);
5077 if (cPairs
&& kern_pair
)
5079 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5080 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5083 return font
->total_kern_pairs
;
5086 #else /* HAVE_FREETYPE */
5088 /*************************************************************************/
5090 BOOL
WineEngInit(void)
5094 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
5098 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
5103 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5108 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
5109 LPWORD pgi
, DWORD flags
)
5114 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
5115 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5118 ERR("called but we don't have FreeType\n");
5122 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5124 ERR("called but we don't have FreeType\n");
5128 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5129 OUTLINETEXTMETRICW
*potm
)
5131 ERR("called but we don't have FreeType\n");
5135 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5138 ERR("called but we don't have FreeType\n");
5142 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5145 ERR("called but we don't have FreeType\n");
5149 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5152 ERR("called but we don't have FreeType\n");
5156 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5157 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5159 ERR("called but we don't have FreeType\n");
5163 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5164 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5166 ERR("called but we don't have FreeType\n");
5170 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5173 ERR("called but we don't have FreeType\n");
5177 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5179 ERR("called but we don't have FreeType\n");
5183 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5189 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5195 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
5201 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5204 return DEFAULT_CHARSET
;
5207 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5212 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5214 FIXME("(%p, %p): stub\n", font
, glyphset
);
5218 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5223 /*************************************************************************
5224 * GetRasterizerCaps (GDI32.@)
5226 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5228 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5230 lprs
->nLanguageID
= 0;
5234 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5236 ERR("called but we don't have FreeType\n");
5240 #endif /* HAVE_FREETYPE */