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
;
323 float scale_x
, scale_y
;
326 OUTLINETEXTMETRICW
*potm
;
328 DWORD total_kern_pairs
;
329 KERNINGPAIR
*kern_pairs
;
332 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 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2443 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2449 static int get_nearest_charset(Face
*face
, int *cp
)
2451 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2452 a single face with the requested charset. The idea is to check if
2453 the selected font supports the current ANSI codepage, if it does
2454 return the corresponding charset, else return the first charset */
2457 int acp
= GetACP(), i
;
2461 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2462 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2463 return csi
.ciCharset
;
2465 for(i
= 0; i
< 32; i
++) {
2467 if(face
->fs
.fsCsb
[0] & fs0
) {
2468 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2470 return csi
.ciCharset
;
2473 FIXME("TCI failing on %x\n", fs0
);
2477 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2478 face
->fs
.fsCsb
[0], face
->file
);
2480 return DEFAULT_CHARSET
;
2483 static GdiFont
*alloc_font(void)
2485 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2487 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2488 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2490 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2491 ret
->total_kern_pairs
= (DWORD
)-1;
2492 ret
->kern_pairs
= NULL
;
2493 list_init(&ret
->hfontlist
);
2494 list_init(&ret
->child_fonts
);
2498 static void free_font(GdiFont
*font
)
2500 struct list
*cursor
, *cursor2
;
2503 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2505 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2506 struct list
*first_hfont
;
2507 HFONTLIST
*hfontlist
;
2508 list_remove(cursor
);
2511 first_hfont
= list_head(&child
->font
->hfontlist
);
2512 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2513 DeleteObject(hfontlist
->hfont
);
2514 HeapFree(GetProcessHeap(), 0, hfontlist
);
2515 free_font(child
->font
);
2517 HeapFree(GetProcessHeap(), 0, child
);
2520 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2521 if (font
->mapping
) unmap_font_file( font
->mapping
);
2522 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2523 HeapFree(GetProcessHeap(), 0, font
->potm
);
2524 HeapFree(GetProcessHeap(), 0, font
->name
);
2525 for (i
= 0; i
< font
->gmsize
; i
++)
2526 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2527 HeapFree(GetProcessHeap(), 0, font
->gm
);
2528 HeapFree(GetProcessHeap(), 0, font
);
2532 /*************************************************************
2535 * load the vdmx entry for the specified height
2538 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2539 ( ( (FT_ULong)_x4 << 24 ) | \
2540 ( (FT_ULong)_x3 << 16 ) | \
2541 ( (FT_ULong)_x2 << 8 ) | \
2544 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2559 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2563 BYTE devXRatio
, devYRatio
;
2564 USHORT numRecs
, numRatios
;
2565 DWORD result
, offset
= -1;
2569 /* For documentation on VDMX records, see
2570 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2573 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2575 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2578 /* FIXME: need the real device aspect ratio */
2582 numRecs
= GET_BE_WORD(hdr
[1]);
2583 numRatios
= GET_BE_WORD(hdr
[2]);
2585 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2586 for(i
= 0; i
< numRatios
; i
++) {
2589 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2590 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2593 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2595 if((ratio
.xRatio
== 0 &&
2596 ratio
.yStartRatio
== 0 &&
2597 ratio
.yEndRatio
== 0) ||
2598 (devXRatio
== ratio
.xRatio
&&
2599 devYRatio
>= ratio
.yStartRatio
&&
2600 devYRatio
<= ratio
.yEndRatio
))
2602 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2603 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2604 offset
= GET_BE_WORD(tmp
);
2610 FIXME("No suitable ratio found\n");
2614 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2616 BYTE startsz
, endsz
;
2619 recs
= GET_BE_WORD(group
.recs
);
2620 startsz
= group
.startsz
;
2621 endsz
= group
.endsz
;
2623 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2625 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2626 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2627 if(result
== GDI_ERROR
) {
2628 FIXME("Failed to retrieve vTable\n");
2633 for(i
= 0; i
< recs
; i
++) {
2634 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2635 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2636 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2638 if(yMax
+ -yMin
== height
) {
2641 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2644 if(yMax
+ -yMin
> height
) {
2647 goto end
; /* failed */
2649 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2650 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2651 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2652 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2658 TRACE("ppem not found for height %d\n", height
);
2662 if(ppem
< startsz
|| ppem
> endsz
)
2665 for(i
= 0; i
< recs
; i
++) {
2667 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2669 if(yPelHeight
> ppem
)
2672 if(yPelHeight
== ppem
) {
2673 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2674 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2675 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2681 HeapFree(GetProcessHeap(), 0, vTable
);
2687 static BOOL
fontcmp(GdiFont
*font
, FONT_DESC
*fd
)
2689 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2690 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2691 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2692 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2693 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2696 static void calc_hash(FONT_DESC
*pfd
)
2698 DWORD hash
= 0, *ptr
, two_chars
;
2702 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2704 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2706 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2708 pwc
= (WCHAR
*)&two_chars
;
2710 *pwc
= toupperW(*pwc
);
2712 *pwc
= toupperW(*pwc
);
2716 hash
^= !pfd
->can_use_bitmap
;
2721 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2726 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2728 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
2729 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2730 fd
.can_use_bitmap
= can_use_bitmap
;
2733 /* try the in-use list */
2734 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2735 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2736 if(!fontcmp(ret
, &fd
)) {
2737 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2738 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2739 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2740 if(hflist
->hfont
== hfont
)
2743 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2744 hflist
->hfont
= hfont
;
2745 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2750 /* then the unused list */
2751 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2752 while(font_elem_ptr
) {
2753 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2754 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2755 if(!fontcmp(ret
, &fd
)) {
2756 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2757 assert(list_empty(&ret
->hfontlist
));
2758 TRACE("Found %p in unused list\n", ret
);
2759 list_remove(&ret
->entry
);
2760 list_add_head(&gdi_font_list
, &ret
->entry
);
2761 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2762 hflist
->hfont
= hfont
;
2763 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2771 /*************************************************************
2772 * create_child_font_list
2774 static BOOL
create_child_font_list(GdiFont
*font
)
2777 SYSTEM_LINKS
*font_link
;
2778 CHILD_FONT
*font_link_entry
, *new_child
;
2780 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2782 if(!strcmpW(font_link
->font_name
, font
->name
))
2784 TRACE("found entry in system list\n");
2785 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2787 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2788 new_child
->face
= font_link_entry
->face
;
2789 new_child
->font
= NULL
;
2790 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2791 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
2801 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2803 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2805 if (pFT_Set_Charmap
)
2808 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2810 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2812 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2814 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2816 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2817 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2819 switch (ft_face
->charmaps
[i
]->platform_id
)
2822 cmap_def
= ft_face
->charmaps
[i
];
2824 case 0: /* Apple Unicode */
2825 cmap0
= ft_face
->charmaps
[i
];
2827 case 1: /* Macintosh */
2828 cmap1
= ft_face
->charmaps
[i
];
2831 cmap2
= ft_face
->charmaps
[i
];
2833 case 3: /* Microsoft */
2834 cmap3
= ft_face
->charmaps
[i
];
2839 if (cmap3
) /* prefer Microsoft cmap table */
2840 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2842 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2844 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2846 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2848 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2850 return ft_err
== FT_Err_Ok
;
2853 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
2856 /*************************************************************
2857 * WineEngCreateFontInstance
2860 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2863 Face
*face
, *best
, *best_bitmap
;
2864 Family
*family
, *last_resort_family
;
2865 struct list
*family_elem_ptr
, *face_elem_ptr
;
2866 INT height
, width
= 0;
2867 unsigned int score
= 0, new_score
;
2868 signed int diff
= 0, newdiff
;
2869 BOOL bd
, it
, can_use_bitmap
;
2874 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2876 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2877 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2878 if(hflist
->hfont
== hfont
)
2882 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
2883 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2885 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2886 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2887 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2890 /* check the cache first */
2891 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2892 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2896 TRACE("not in cache\n");
2897 if(list_empty(&font_list
)) /* No fonts installed */
2899 TRACE("No fonts installed\n");
2902 if(!have_installed_roman_font
)
2904 TRACE("No roman font installed\n");
2910 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
2911 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
2912 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
2913 calc_hash(&ret
->font_desc
);
2914 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2915 hflist
->hfont
= hfont
;
2916 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2919 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2920 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2921 original value lfCharSet. Note this is a special case for
2922 Symbol and doesn't happen at least for "Wingdings*" */
2924 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
2925 lf
.lfCharSet
= SYMBOL_CHARSET
;
2927 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
2928 switch(lf
.lfCharSet
) {
2929 case DEFAULT_CHARSET
:
2930 csi
.fs
.fsCsb
[0] = 0;
2933 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
2934 csi
.fs
.fsCsb
[0] = 0;
2940 if(lf
.lfFaceName
[0] != '\0') {
2942 SYSTEM_LINKS
*font_link
;
2943 CHILD_FONT
*font_link_entry
;
2945 psub
= get_font_subst(&font_subst_list
, lf
.lfFaceName
, lf
.lfCharSet
);
2948 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
2949 debugstr_w(psub
->to
.name
));
2950 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2953 /* We want a match on name and charset or just name if
2954 charset was DEFAULT_CHARSET. If the latter then
2955 we fixup the returned charset later in get_nearest_charset
2956 where we'll either use the charset of the current ansi codepage
2957 or if that's unavailable the first charset that the font supports.
2959 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2960 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2961 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2962 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2963 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2964 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2965 if(face
->scalable
|| can_use_bitmap
)
2972 * Try check the SystemLink list first for a replacement font.
2973 * We may find good replacements there.
2975 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2977 if(!strcmpiW(font_link
->font_name
, lf
.lfFaceName
))
2979 TRACE("found entry in system list\n");
2980 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2982 face
= font_link_entry
->face
;
2983 family
= face
->family
;
2984 if(csi
.fs
.fsCsb
[0] &
2985 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
2987 if(face
->scalable
|| can_use_bitmap
)
2995 /* If requested charset was DEFAULT_CHARSET then try using charset
2996 corresponding to the current ansi codepage */
2997 if(!csi
.fs
.fsCsb
[0]) {
2999 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3000 FIXME("TCI failed on codepage %d\n", acp
);
3001 csi
.fs
.fsCsb
[0] = 0;
3003 lf
.lfCharSet
= csi
.ciCharset
;
3006 /* Face families are in the top 4 bits of lfPitchAndFamily,
3007 so mask with 0xF0 before testing */
3009 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3010 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3011 strcpyW(lf
.lfFaceName
, defFixed
);
3012 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3013 strcpyW(lf
.lfFaceName
, defSerif
);
3014 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3015 strcpyW(lf
.lfFaceName
, defSans
);
3017 strcpyW(lf
.lfFaceName
, defSans
);
3018 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3019 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3020 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3021 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3022 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3023 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3024 if(face
->scalable
|| can_use_bitmap
)
3030 last_resort_family
= NULL
;
3031 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3032 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3033 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3034 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3035 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3038 if(can_use_bitmap
&& !last_resort_family
)
3039 last_resort_family
= family
;
3044 if(last_resort_family
) {
3045 family
= last_resort_family
;
3046 csi
.fs
.fsCsb
[0] = 0;
3050 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3051 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3052 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3053 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3054 if(face
->scalable
) {
3055 csi
.fs
.fsCsb
[0] = 0;
3056 WARN("just using first face for now\n");
3059 if(can_use_bitmap
&& !last_resort_family
)
3060 last_resort_family
= family
;
3063 if(!last_resort_family
) {
3064 FIXME("can't find a single appropriate font - bailing\n");
3069 WARN("could only find a bitmap font - this will probably look awful!\n");
3070 family
= last_resort_family
;
3071 csi
.fs
.fsCsb
[0] = 0;
3074 it
= lf
.lfItalic
? 1 : 0;
3075 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3077 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
3078 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
3080 face
= best
= best_bitmap
= NULL
;
3081 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3083 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3085 new_score
= (face
->Italic
^ it
) + (face
->Bold
^ bd
);
3086 if(!best
|| new_score
<= score
)
3088 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3089 face
->Italic
, face
->Bold
, it
, bd
);
3092 if(best
->scalable
&& score
== 0) break;
3096 newdiff
= height
- (signed int)(best
->size
.height
);
3098 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3099 if(!best_bitmap
|| new_score
< score
||
3100 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3102 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3105 if(score
== 0 && diff
== 0) break;
3112 face
= best
->scalable
? best
: best_bitmap
;
3113 ret
->fake_italic
= (it
&& !face
->Italic
);
3114 ret
->fake_bold
= (bd
&& !face
->Bold
);
3116 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
3118 if(csi
.fs
.fsCsb
[0]) {
3119 ret
->charset
= lf
.lfCharSet
;
3120 ret
->codepage
= csi
.ciACP
;
3123 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3125 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3126 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3131 ret
->aveWidth
= abs(lf
.lfWidth
);
3133 if(!face
->scalable
) {
3134 ret
->ppem
= face
->size
.height
;
3135 if (height
!= 0) ret
->ppem
+= diff
;
3137 width
= face
->size
.x_ppem
>> 6;
3138 height
= face
->size
.y_ppem
>> 6;
3140 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3148 ret
->ntmFlags
= face
->ntmFlags
;
3150 if (ret
->charset
== SYMBOL_CHARSET
&&
3151 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3154 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3158 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3161 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3162 ret
->name
= strdupW(family
->FamilyName
);
3163 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3164 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3165 create_child_font_list(ret
);
3167 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3169 list_add_head(&gdi_font_list
, &ret
->entry
);
3173 static void dump_gdi_font_list(void)
3176 struct list
*elem_ptr
;
3178 TRACE("---------- gdiFont Cache ----------\n");
3179 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3180 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3181 TRACE("gdiFont=%p %s %d\n",
3182 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3185 TRACE("---------- Unused gdiFont Cache ----------\n");
3186 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3187 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3188 TRACE("gdiFont=%p %s %d\n",
3189 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3193 /*************************************************************
3194 * WineEngDestroyFontInstance
3196 * free the gdiFont associated with this handle
3199 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3204 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3207 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3209 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3210 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3211 if(hflist
->hfont
== handle
)
3213 TRACE("removing child font %p from child list\n", gdiFont
);
3214 list_remove(&gdiFont
->entry
);
3219 TRACE("destroying hfont=%p\n", handle
);
3221 dump_gdi_font_list();
3223 font_elem_ptr
= list_head(&gdi_font_list
);
3224 while(font_elem_ptr
) {
3225 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3226 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3228 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3229 while(hfontlist_elem_ptr
) {
3230 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3231 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3232 if(hflist
->hfont
== handle
) {
3233 list_remove(&hflist
->entry
);
3234 HeapFree(GetProcessHeap(), 0, hflist
);
3238 if(list_empty(&gdiFont
->hfontlist
)) {
3239 TRACE("Moving to Unused list\n");
3240 list_remove(&gdiFont
->entry
);
3241 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3246 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3247 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3248 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3249 while(font_elem_ptr
) {
3250 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3251 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3252 TRACE("freeing %p\n", gdiFont
);
3253 list_remove(&gdiFont
->entry
);
3259 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3260 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3265 if (face
->cache_valid
)
3268 memcpy(pelf
,&face
->elf
,sizeof(ENUMLOGFONTEXW
));
3269 memcpy(pntm
,&face
->ntm
,sizeof(NEWTEXTMETRICEXW
));
3270 *ptype
= face
->type
;
3274 font
= alloc_font();
3276 if(face
->scalable
) {
3280 height
= face
->size
.y_ppem
>> 6;
3281 width
= face
->size
.x_ppem
>> 6;
3284 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3290 font
->name
= strdupW(face
->family
->FamilyName
);
3291 font
->ntmFlags
= face
->ntmFlags
;
3293 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
3295 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3297 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3299 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3301 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3302 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3304 lstrcpynW(pelf
->elfFullName
,
3305 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
3307 lstrcpynW(pelf
->elfStyle
,
3308 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
3313 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
3315 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3317 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3318 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
3319 pelf
->elfStyle
[0] = '\0';
3322 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
3323 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3324 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3325 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
3327 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3329 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
3330 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3331 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
3332 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
3333 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
3334 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
3335 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
3336 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3337 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3338 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3339 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3342 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
3343 *ptype
|= TRUETYPE_FONTTYPE
;
3344 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
3345 *ptype
|= DEVICE_FONTTYPE
;
3346 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
3347 *ptype
|= RASTER_FONTTYPE
;
3349 memcpy(&face
->elf
,pelf
,sizeof(ENUMLOGFONTEXW
));
3350 memcpy(&face
->ntm
,pntm
,sizeof(NEWTEXTMETRICEXW
));
3351 face
->type
= *ptype
;
3352 face
->cache_valid
= TRUE
;
3357 /*************************************************************
3361 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3365 struct list
*family_elem_ptr
, *face_elem_ptr
;
3367 NEWTEXTMETRICEXW ntm
;
3368 DWORD type
, ret
= 1;
3374 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3376 if(plf
->lfFaceName
[0]) {
3378 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3381 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3382 debugstr_w(psub
->to
.name
));
3383 memcpy(&lf
, plf
, sizeof(lf
));
3384 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3388 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3389 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3390 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3391 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3392 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3393 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3394 for(i
= 0; i
< 32; i
++) {
3395 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3396 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3397 strcpyW(elf
.elfScript
, OEM_DOSW
);
3398 i
= 32; /* break out of loop */
3399 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3402 fs
.fsCsb
[0] = 1L << i
;
3404 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3406 csi
.ciCharset
= DEFAULT_CHARSET
;
3407 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3408 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3409 elf
.elfLogFont
.lfCharSet
=
3410 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3412 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3414 FIXME("Unknown elfscript for bit %d\n", i
);
3417 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3418 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3419 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3420 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3421 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3422 ntm
.ntmTm
.ntmFlags
);
3423 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3430 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3431 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3432 face_elem_ptr
= list_head(&family
->faces
);
3433 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3434 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3435 for(i
= 0; i
< 32; i
++) {
3436 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3437 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3438 strcpyW(elf
.elfScript
, OEM_DOSW
);
3439 i
= 32; /* break out of loop */
3440 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3443 fs
.fsCsb
[0] = 1L << i
;
3445 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3447 csi
.ciCharset
= DEFAULT_CHARSET
;
3448 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3449 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3450 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3453 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3455 FIXME("Unknown elfscript for bit %d\n", i
);
3458 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3459 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3460 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3461 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3462 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3463 ntm
.ntmTm
.ntmFlags
);
3464 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3473 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3475 pt
->x
.value
= vec
->x
>> 6;
3476 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3477 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3478 pt
->y
.value
= vec
->y
>> 6;
3479 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3480 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3484 /***************************************************
3485 * According to the MSDN documentation on WideCharToMultiByte,
3486 * certain codepages cannot set the default_used parameter.
3487 * This returns TRUE if the codepage can set that parameter, false else
3488 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3490 static BOOL
codepage_sets_default_used(UINT codepage
)
3503 static FT_UInt
get_glyph_index(GdiFont
*font
, UINT glyph
)
3505 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
3506 WCHAR wc
= (WCHAR
)glyph
;
3508 BOOL
*default_used_pointer
;
3511 default_used_pointer
= NULL
;
3512 default_used
= FALSE
;
3513 if (codepage_sets_default_used(font
->codepage
))
3514 default_used_pointer
= &default_used
;
3515 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
3518 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
3519 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
3523 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
3524 glyph
= glyph
+ 0xf000;
3525 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
3528 /*************************************************************
3529 * WineEngGetGlyphIndices
3531 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3533 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
3534 LPWORD pgi
, DWORD flags
)
3537 WCHAR default_char
= 0;
3540 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0x001f; /* Indicate non existence */
3542 for(i
= 0; i
< count
; i
++)
3544 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
3549 WineEngGetTextMetrics(font
, &textm
);
3550 default_char
= textm
.tmDefaultChar
;
3552 pgi
[i
] = default_char
;
3558 /*************************************************************
3559 * WineEngGetGlyphOutline
3561 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3562 * except that the first parameter is the HWINEENGFONT of the font in
3563 * question rather than an HDC.
3566 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
3567 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3570 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
3571 FT_Face ft_face
= incoming_font
->ft_face
;
3572 GdiFont
*font
= incoming_font
;
3573 FT_UInt glyph_index
;
3574 DWORD width
, height
, pitch
, needed
= 0;
3575 FT_Bitmap ft_bitmap
;
3577 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
3579 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3580 float widthRatio
= 1.0, heightRatio
= 1.0;
3581 FT_Matrix transMat
= identityMat
;
3582 BOOL needsTransform
= FALSE
;
3585 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
3586 buflen
, buf
, lpmat
);
3588 if(format
& GGO_GLYPH_INDEX
) {
3589 glyph_index
= glyph
;
3590 format
&= ~GGO_GLYPH_INDEX
;
3592 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
3593 ft_face
= font
->ft_face
;
3596 if(glyph_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
3597 font
->gmsize
= (glyph_index
/ GM_BLOCK_SIZE
+ 1);
3598 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
3599 font
->gmsize
* sizeof(GM
*));
3601 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] != NULL
&& FONT_GM(font
,glyph_index
)->init
) {
3602 *lpgm
= FONT_GM(font
,glyph_index
)->gm
;
3603 return 1; /* FIXME */
3607 if (!font
->gm
[glyph_index
/ GM_BLOCK_SIZE
])
3608 font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3610 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) || lpmat
)
3611 load_flags
|= FT_LOAD_NO_BITMAP
;
3613 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
3616 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
3620 /* Scaling factor */
3621 if (font
->scale_x
!= 0.0)
3623 widthRatio
= font
->scale_x
;
3624 heightRatio
= font
->scale_y
;
3627 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
3628 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
3630 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
3632 bbx
= (right
- left
) >> 6;
3634 /* Scaling transform */
3635 if(font
->aveWidth
) {
3637 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
3640 scaleMat
.yy
= FT_FixedFromFloat(heightRatio
);
3642 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
3643 needsTransform
= TRUE
;
3646 /* Slant transform */
3647 if (font
->fake_italic
) {
3650 slantMat
.xx
= (1 << 16);
3651 slantMat
.xy
= ((1 << 16) >> 2);
3653 slantMat
.yy
= (1 << 16);
3654 pFT_Matrix_Multiply(&slantMat
, &transMat
);
3655 needsTransform
= TRUE
;
3658 /* Rotation transform */
3659 if(font
->orientation
) {
3660 FT_Matrix rotationMat
;
3662 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
3663 pFT_Vector_Unit(&vecAngle
, angle
);
3664 rotationMat
.xx
= vecAngle
.x
;
3665 rotationMat
.xy
= -vecAngle
.y
;
3666 rotationMat
.yx
= -rotationMat
.xy
;
3667 rotationMat
.yy
= rotationMat
.xx
;
3669 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
3670 needsTransform
= TRUE
;
3673 /* Extra transformation specified by caller */
3676 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
3677 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
3678 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
3679 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
3680 pFT_Matrix_Multiply(&extraMat
, &transMat
);
3681 needsTransform
= TRUE
;
3684 if(!needsTransform
) {
3685 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
3686 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
3687 ft_face
->glyph
->metrics
.height
) & -64;
3688 lpgm
->gmCellIncX
= adv
;
3689 lpgm
->gmCellIncY
= 0;
3693 for(xc
= 0; xc
< 2; xc
++) {
3694 for(yc
= 0; yc
< 2; yc
++) {
3695 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
3696 xc
* ft_face
->glyph
->metrics
.width
);
3697 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
3698 yc
* ft_face
->glyph
->metrics
.height
;
3699 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
3700 pFT_Vector_Transform(&vec
, &transMat
);
3701 if(xc
== 0 && yc
== 0) {
3702 left
= right
= vec
.x
;
3703 top
= bottom
= vec
.y
;
3705 if(vec
.x
< left
) left
= vec
.x
;
3706 else if(vec
.x
> right
) right
= vec
.x
;
3707 if(vec
.y
< bottom
) bottom
= vec
.y
;
3708 else if(vec
.y
> top
) top
= vec
.y
;
3713 right
= (right
+ 63) & -64;
3714 bottom
= bottom
& -64;
3715 top
= (top
+ 63) & -64;
3717 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
3718 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
3720 pFT_Vector_Transform(&vec
, &transMat
);
3721 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
3722 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
3724 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
3725 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
3726 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
3727 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
3729 if(format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
)
3731 FONT_GM(font
,glyph_index
)->gm
= *lpgm
;
3732 FONT_GM(font
,glyph_index
)->adv
= adv
;
3733 FONT_GM(font
,glyph_index
)->lsb
= lsb
;
3734 FONT_GM(font
,glyph_index
)->bbx
= bbx
;
3735 FONT_GM(font
,glyph_index
)->init
= TRUE
;
3738 if(format
== GGO_METRICS
)
3739 return 1; /* FIXME */
3741 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) {
3742 TRACE("loaded a bitmap\n");
3748 width
= lpgm
->gmBlackBoxX
;
3749 height
= lpgm
->gmBlackBoxY
;
3750 pitch
= ((width
+ 31) >> 5) << 2;
3751 needed
= pitch
* height
;
3753 if(!buf
|| !buflen
) break;
3755 switch(ft_face
->glyph
->format
) {
3756 case ft_glyph_format_bitmap
:
3758 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3759 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
3760 INT h
= ft_face
->glyph
->bitmap
.rows
;
3762 memcpy(dst
, src
, w
);
3763 src
+= ft_face
->glyph
->bitmap
.pitch
;
3769 case ft_glyph_format_outline
:
3770 ft_bitmap
.width
= width
;
3771 ft_bitmap
.rows
= height
;
3772 ft_bitmap
.pitch
= pitch
;
3773 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
3774 ft_bitmap
.buffer
= buf
;
3776 if(needsTransform
) {
3777 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3780 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3782 /* Note: FreeType will only set 'black' bits for us. */
3783 memset(buf
, 0, needed
);
3784 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3788 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3793 case GGO_GRAY2_BITMAP
:
3794 case GGO_GRAY4_BITMAP
:
3795 case GGO_GRAY8_BITMAP
:
3796 case WINE_GGO_GRAY16_BITMAP
:
3798 unsigned int mult
, row
, col
;
3801 width
= lpgm
->gmBlackBoxX
;
3802 height
= lpgm
->gmBlackBoxY
;
3803 pitch
= (width
+ 3) / 4 * 4;
3804 needed
= pitch
* height
;
3806 if(!buf
|| !buflen
) break;
3808 switch(ft_face
->glyph
->format
) {
3809 case ft_glyph_format_bitmap
:
3811 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3812 INT h
= ft_face
->glyph
->bitmap
.rows
;
3815 for(x
= 0; x
< pitch
; x
++)
3816 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
3817 src
+= ft_face
->glyph
->bitmap
.pitch
;
3822 case ft_glyph_format_outline
:
3824 ft_bitmap
.width
= width
;
3825 ft_bitmap
.rows
= height
;
3826 ft_bitmap
.pitch
= pitch
;
3827 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
3828 ft_bitmap
.buffer
= buf
;
3831 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3833 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3835 memset(ft_bitmap
.buffer
, 0, buflen
);
3837 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3839 if(format
== GGO_GRAY2_BITMAP
)
3841 else if(format
== GGO_GRAY4_BITMAP
)
3843 else if(format
== GGO_GRAY8_BITMAP
)
3845 else /* format == WINE_GGO_GRAY16_BITMAP */
3851 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3856 for(row
= 0; row
< height
; row
++) {
3858 for(col
= 0; col
< width
; col
++, ptr
++) {
3859 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
3868 int contour
, point
= 0, first_pt
;
3869 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3870 TTPOLYGONHEADER
*pph
;
3872 DWORD pph_start
, cpfx
, type
;
3874 if(buflen
== 0) buf
= NULL
;
3876 if (needsTransform
&& buf
) {
3877 pFT_Outline_Transform(outline
, &transMat
);
3880 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3882 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3885 pph
->dwType
= TT_POLYGON_TYPE
;
3886 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3888 needed
+= sizeof(*pph
);
3890 while(point
<= outline
->contours
[contour
]) {
3891 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3892 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3893 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3897 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3900 } while(point
<= outline
->contours
[contour
] &&
3901 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3902 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3903 /* At the end of a contour Windows adds the start point, but
3905 if(point
> outline
->contours
[contour
] &&
3906 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3908 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3910 } else if(point
<= outline
->contours
[contour
] &&
3911 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3912 /* add closing pt for bezier */
3914 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3922 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3925 pph
->cb
= needed
- pph_start
;
3931 /* Convert the quadratic Beziers to cubic Beziers.
3932 The parametric eqn for a cubic Bezier is, from PLRM:
3933 r(t) = at^3 + bt^2 + ct + r0
3934 with the control points:
3939 A quadratic Beizer has the form:
3940 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3942 So equating powers of t leads to:
3943 r1 = 2/3 p1 + 1/3 p0
3944 r2 = 2/3 p1 + 1/3 p2
3945 and of course r0 = p0, r3 = p2
3948 int contour
, point
= 0, first_pt
;
3949 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3950 TTPOLYGONHEADER
*pph
;
3952 DWORD pph_start
, cpfx
, type
;
3953 FT_Vector cubic_control
[4];
3954 if(buflen
== 0) buf
= NULL
;
3956 if (needsTransform
&& buf
) {
3957 pFT_Outline_Transform(outline
, &transMat
);
3960 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3962 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3965 pph
->dwType
= TT_POLYGON_TYPE
;
3966 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3968 needed
+= sizeof(*pph
);
3970 while(point
<= outline
->contours
[contour
]) {
3971 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3972 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3973 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3976 if(type
== TT_PRIM_LINE
) {
3978 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3982 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3985 /* FIXME: Possible optimization in endpoint calculation
3986 if there are two consecutive curves */
3987 cubic_control
[0] = outline
->points
[point
-1];
3988 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3989 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3990 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3991 cubic_control
[0].x
>>= 1;
3992 cubic_control
[0].y
>>= 1;
3994 if(point
+1 > outline
->contours
[contour
])
3995 cubic_control
[3] = outline
->points
[first_pt
];
3997 cubic_control
[3] = outline
->points
[point
+1];
3998 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
3999 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
4000 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
4001 cubic_control
[3].x
>>= 1;
4002 cubic_control
[3].y
>>= 1;
4005 /* r1 = 1/3 p0 + 2/3 p1
4006 r2 = 1/3 p2 + 2/3 p1 */
4007 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
4008 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
4009 cubic_control
[2] = cubic_control
[1];
4010 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
4011 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
4012 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
4013 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
4015 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
4016 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
4017 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
4022 } while(point
<= outline
->contours
[contour
] &&
4023 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4024 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4025 /* At the end of a contour Windows adds the start point,
4026 but only for Beziers and we've already done that.
4028 if(point
<= outline
->contours
[contour
] &&
4029 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4030 /* This is the closing pt of a bezier, but we've already
4031 added it, so just inc point and carry on */
4038 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4041 pph
->cb
= needed
- pph_start
;
4047 FIXME("Unsupported format %d\n", format
);
4053 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
4055 FT_Face ft_face
= font
->ft_face
;
4056 #ifdef HAVE_FREETYPE_FTWINFNT_H
4057 FT_WinFNT_HeaderRec winfnt_header
;
4059 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
4060 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
4061 font
->potm
->otmSize
= size
;
4063 #define TM font->potm->otmTextMetrics
4064 #ifdef HAVE_FREETYPE_FTWINFNT_H
4065 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
4067 TM
.tmHeight
= winfnt_header
.pixel_height
;
4068 TM
.tmAscent
= winfnt_header
.ascent
;
4069 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
4070 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
4071 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
4072 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
4073 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4074 TM
.tmWeight
= winfnt_header
.weight
;
4076 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4077 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4078 TM
.tmFirstChar
= winfnt_header
.first_char
;
4079 TM
.tmLastChar
= winfnt_header
.last_char
;
4080 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4081 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4082 TM
.tmItalic
= winfnt_header
.italic
;
4083 TM
.tmUnderlined
= font
->underline
;
4084 TM
.tmStruckOut
= font
->strikeout
;
4085 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4086 TM
.tmCharSet
= winfnt_header
.charset
;
4091 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4092 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4093 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4094 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4095 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4096 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4097 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4098 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4100 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4101 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4103 TM
.tmLastChar
= 255;
4104 TM
.tmDefaultChar
= 32;
4105 TM
.tmBreakChar
= 32;
4106 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4107 TM
.tmUnderlined
= font
->underline
;
4108 TM
.tmStruckOut
= font
->strikeout
;
4109 /* NB inverted meaning of TMPF_FIXED_PITCH */
4110 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4111 TM
.tmCharSet
= font
->charset
;
4119 static void scale_font_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4121 if (font
->scale_x
== 0.0)
4123 if (FT_IS_SCALABLE(font
->ft_face
) || !font
->ppem
)
4124 font
->scale_y
= 1.0;
4127 font
->scale_y
= (float)font
->ppem
* font
->font_desc
.matrix
.eM22
;
4128 font
->scale_y
/= (float)font
->potm
->otmTextMetrics
.tmHeight
;
4133 font
->scale_x
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4134 font
->scale_x
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4137 font
->scale_x
= font
->scale_y
;
4139 TRACE("font scale x: %f y: %f\n", font
->scale_x
, font
->scale_y
);
4141 ptm
->tmHeight
= (float)ptm
->tmHeight
* font
->scale_y
;
4142 ptm
->tmAscent
= (float)ptm
->tmAscent
* font
->scale_y
;
4143 ptm
->tmDescent
= (float)ptm
->tmDescent
* font
->scale_y
;
4144 ptm
->tmInternalLeading
= (float)ptm
->tmInternalLeading
* font
->scale_y
;
4145 ptm
->tmExternalLeading
= (float)ptm
->tmExternalLeading
* font
->scale_y
;
4147 ptm
->tmAveCharWidth
= (float)ptm
->tmAveCharWidth
* font
->scale_x
;
4148 ptm
->tmMaxCharWidth
= (float)ptm
->tmMaxCharWidth
* font
->scale_x
;
4151 /*************************************************************
4152 * WineEngGetTextMetrics
4155 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4158 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4159 if(!get_bitmap_text_metrics(font
))
4162 if(!font
->potm
) return FALSE
;
4163 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
4164 scale_font_metrics(font
, ptm
);
4170 /*************************************************************
4171 * WineEngGetOutlineTextMetrics
4174 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4175 OUTLINETEXTMETRICW
*potm
)
4177 FT_Face ft_face
= font
->ft_face
;
4178 UINT needed
, lenfam
, lensty
, ret
;
4180 TT_HoriHeader
*pHori
;
4181 TT_Postscript
*pPost
;
4182 FT_Fixed x_scale
, y_scale
;
4183 WCHAR
*family_nameW
, *style_nameW
;
4184 static const WCHAR spaceW
[] = {' ', '\0'};
4186 INT ascent
, descent
;
4188 TRACE("font=%p\n", font
);
4190 if(!FT_IS_SCALABLE(ft_face
))
4194 if(cbSize
>= font
->potm
->otmSize
)
4196 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4197 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4199 return font
->potm
->otmSize
;
4203 needed
= sizeof(*potm
);
4205 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
4206 family_nameW
= strdupW(font
->name
);
4208 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
4210 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
4211 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
4212 style_nameW
, lensty
/sizeof(WCHAR
));
4214 /* These names should be read from the TT name table */
4216 /* length of otmpFamilyName */
4219 /* length of otmpFaceName */
4220 if(!strcasecmp(ft_face
->style_name
, "regular")) {
4221 needed
+= lenfam
; /* just the family name */
4223 needed
+= lenfam
+ lensty
; /* family + " " + style */
4226 /* length of otmpStyleName */
4229 /* length of otmpFullName */
4230 needed
+= lenfam
+ lensty
;
4233 x_scale
= ft_face
->size
->metrics
.x_scale
;
4234 y_scale
= ft_face
->size
->metrics
.y_scale
;
4236 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4238 FIXME("Can't find OS/2 table - not TT font?\n");
4243 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4245 FIXME("Can't find HHEA table - not TT font?\n");
4250 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
4252 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",
4253 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
4254 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
4255 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
4256 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
4257 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
4259 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
4260 font
->potm
->otmSize
= needed
;
4262 #define TM font->potm->otmTextMetrics
4264 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
4265 ascent
= pHori
->Ascender
;
4266 descent
= -pHori
->Descender
;
4268 ascent
= pOS2
->usWinAscent
;
4269 descent
= pOS2
->usWinDescent
;
4273 TM
.tmAscent
= font
->yMax
;
4274 TM
.tmDescent
= -font
->yMin
;
4275 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4277 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4278 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4279 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4280 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4283 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4286 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4288 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4289 ((ascent
+ descent
) -
4290 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4292 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4293 if (TM
.tmAveCharWidth
== 0) {
4294 TM
.tmAveCharWidth
= 1;
4296 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4297 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4299 TM
.tmDigitizedAspectX
= 300;
4300 TM
.tmDigitizedAspectY
= 300;
4301 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4302 * symbol range to 0 - f0ff
4304 if (font
->charset
== SYMBOL_CHARSET
)
4307 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4308 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4309 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4310 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4311 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4312 TM
.tmUnderlined
= font
->underline
;
4313 TM
.tmStruckOut
= font
->strikeout
;
4315 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4316 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4317 (pOS2
->version
== 0xFFFFU
||
4318 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4319 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4321 TM
.tmPitchAndFamily
= 0;
4323 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4324 case PAN_FAMILY_SCRIPT
:
4325 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4327 case PAN_FAMILY_DECORATIVE
:
4328 case PAN_FAMILY_PICTORIAL
:
4329 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4331 case PAN_FAMILY_TEXT_DISPLAY
:
4332 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4333 TM
.tmPitchAndFamily
= FF_MODERN
;
4335 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4336 case PAN_SERIF_NORMAL_SANS
:
4337 case PAN_SERIF_OBTUSE_SANS
:
4338 case PAN_SERIF_PERP_SANS
:
4339 TM
.tmPitchAndFamily
|= FF_SWISS
;
4342 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4347 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4350 if(FT_IS_SCALABLE(ft_face
))
4351 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4353 if(FT_IS_SFNT(ft_face
))
4355 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
4356 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
4358 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4361 TM
.tmCharSet
= font
->charset
;
4364 font
->potm
->otmFiller
= 0;
4365 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4366 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4367 font
->potm
->otmfsType
= pOS2
->fsType
;
4368 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4369 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4370 font
->potm
->otmItalicAngle
= 0; /* POST table */
4371 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4372 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4373 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4374 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4375 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4376 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
4377 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4378 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
4379 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
4380 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
4381 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
4382 font
->potm
->otmMacDescent
= 0;
4383 font
->potm
->otmMacLineGap
= 0;
4384 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
4385 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
4386 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
4387 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
4388 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
4389 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
4390 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
4391 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
4392 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
4393 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
4394 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
4396 font
->potm
->otmsUnderscoreSize
= 0;
4397 font
->potm
->otmsUnderscorePosition
= 0;
4399 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
4400 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
4403 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4404 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
4405 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
4406 strcpyW((WCHAR
*)cp
, family_nameW
);
4408 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
4409 strcpyW((WCHAR
*)cp
, style_nameW
);
4411 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
4412 strcpyW((WCHAR
*)cp
, family_nameW
);
4413 if(strcasecmp(ft_face
->style_name
, "regular")) {
4414 strcatW((WCHAR
*)cp
, spaceW
);
4415 strcatW((WCHAR
*)cp
, style_nameW
);
4416 cp
+= lenfam
+ lensty
;
4419 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
4420 strcpyW((WCHAR
*)cp
, family_nameW
);
4421 strcatW((WCHAR
*)cp
, spaceW
);
4422 strcatW((WCHAR
*)cp
, style_nameW
);
4425 if(potm
&& needed
<= cbSize
)
4427 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4428 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4432 HeapFree(GetProcessHeap(), 0, style_nameW
);
4433 HeapFree(GetProcessHeap(), 0, family_nameW
);
4438 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
4440 HFONTLIST
*hfontlist
;
4441 child
->font
= alloc_font();
4442 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
4443 if(!child
->font
->ft_face
)
4445 free_font(child
->font
);
4450 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
4451 child
->font
->orientation
= font
->orientation
;
4452 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
4453 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
4454 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
4455 child
->font
->base_font
= font
;
4456 list_add_head(&child_font_list
, &child
->font
->entry
);
4457 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
4461 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
4464 CHILD_FONT
*child_font
;
4467 font
= font
->base_font
;
4469 *linked_font
= font
;
4471 if((*glyph
= get_glyph_index(font
, c
)))
4474 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
4476 if(!child_font
->font
)
4477 if(!load_child_font(font
, child_font
))
4480 if(!child_font
->font
->ft_face
)
4482 g
= get_glyph_index(child_font
->font
, c
);
4486 *linked_font
= child_font
->font
;
4493 /*************************************************************
4494 * WineEngGetCharWidth
4497 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4502 FT_UInt glyph_index
;
4503 GdiFont
*linked_font
;
4505 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4507 for(c
= firstChar
; c
<= lastChar
; c
++) {
4508 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4509 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4510 &gm
, 0, NULL
, NULL
);
4511 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
4516 /*************************************************************
4517 * WineEngGetCharABCWidths
4520 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4525 FT_UInt glyph_index
;
4526 GdiFont
*linked_font
;
4528 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4530 if(!FT_IS_SCALABLE(font
->ft_face
))
4533 for(c
= firstChar
; c
<= lastChar
; c
++) {
4534 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4535 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4536 &gm
, 0, NULL
, NULL
);
4537 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
4538 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
4539 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
4540 FONT_GM(linked_font
,glyph_index
)->bbx
;
4545 /*************************************************************
4546 * WineEngGetCharABCWidthsI
4549 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4554 FT_UInt glyph_index
;
4555 GdiFont
*linked_font
;
4557 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
4560 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
4562 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
4563 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4564 &gm
, 0, NULL
, NULL
);
4565 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
4566 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
4567 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
4568 - FONT_GM(linked_font
,c
)->bbx
;
4571 for(c
= 0; c
< count
; c
++) {
4572 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4573 &gm
, 0, NULL
, NULL
);
4574 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
4575 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
4576 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
4577 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
4583 /*************************************************************
4584 * WineEngGetTextExtentExPoint
4587 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4588 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4594 FT_UInt glyph_index
;
4595 GdiFont
*linked_font
;
4597 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
4601 WineEngGetTextMetrics(font
, &tm
);
4602 size
->cy
= tm
.tmHeight
;
4604 for(idx
= 0; idx
< count
; idx
++) {
4605 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
4606 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4607 &gm
, 0, NULL
, NULL
);
4608 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
4610 if (! pnfit
|| ext
<= max_ext
) {
4620 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4624 /*************************************************************
4625 * WineEngGetTextExtentExPointI
4628 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4629 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4636 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
4639 WineEngGetTextMetrics(font
, &tm
);
4640 size
->cy
= tm
.tmHeight
;
4642 for(idx
= 0; idx
< count
; idx
++) {
4643 WineEngGetGlyphOutline(font
, indices
[idx
],
4644 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
4646 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
4648 if (! pnfit
|| ext
<= max_ext
) {
4658 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4662 /*************************************************************
4663 * WineEngGetFontData
4666 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4669 FT_Face ft_face
= font
->ft_face
;
4673 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4674 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
4675 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
4677 if(!FT_IS_SFNT(ft_face
))
4685 if(table
) { /* MS tags differ in endidness from FT ones */
4686 table
= table
>> 24 | table
<< 24 |
4687 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
4690 /* make sure value of len is the value freetype says it needs */
4693 FT_ULong needed
= 0;
4694 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
4695 if( !err
&& needed
< len
) len
= needed
;
4697 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
4700 TRACE("Can't find table %c%c%c%c\n",
4701 /* bytes were reversed */
4702 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4703 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4709 /*************************************************************
4710 * WineEngGetTextFace
4713 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4716 lstrcpynW(str
, font
->name
, count
);
4717 return strlenW(font
->name
);
4719 return strlenW(font
->name
) + 1;
4722 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4724 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
4725 return font
->charset
;
4728 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4730 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
4731 struct list
*first_hfont
;
4734 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
4735 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
4736 if(font
== linked_font
)
4737 *new_hfont
= dc
->hFont
;
4740 first_hfont
= list_head(&linked_font
->hfontlist
);
4741 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
4747 /* Retrieve a list of supported Unicode ranges for a given font.
4748 * Can be called with NULL gs to calculate the buffer size. Returns
4749 * the number of ranges found.
4751 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
4753 DWORD num_ranges
= 0;
4755 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4758 FT_ULong char_code
, char_code_prev
;
4761 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
4763 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4764 face
->num_glyphs
, glyph_code
, char_code
);
4766 if (!glyph_code
) return 0;
4770 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4771 gs
->ranges
[0].cGlyphs
= 0;
4772 gs
->cGlyphsSupported
= 0;
4778 if (char_code
< char_code_prev
)
4780 ERR("expected increasing char code from FT_Get_Next_Char\n");
4783 if (char_code
- char_code_prev
> 1)
4788 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4789 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4790 gs
->cGlyphsSupported
++;
4795 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4796 gs
->cGlyphsSupported
++;
4798 char_code_prev
= char_code
;
4799 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
4803 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
4808 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
4811 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
4813 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
4816 glyphset
->cbThis
= size
;
4817 glyphset
->cRanges
= num_ranges
;
4822 /*************************************************************
4825 BOOL
WineEngFontIsLinked(GdiFont
*font
)
4827 return !list_empty(&font
->child_fonts
);
4830 static BOOL
is_hinting_enabled(void)
4832 /* Use the >= 2.2.0 function if available */
4833 if(pFT_Get_TrueType_Engine_Type
)
4835 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
4836 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
4838 #ifdef FT_DRIVER_HAS_HINTER
4843 /* otherwise if we've been compiled with < 2.2.0 headers
4844 use the internal macro */
4845 mod
= pFT_Get_Module(library
, "truetype");
4846 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
4854 /*************************************************************************
4855 * GetRasterizerCaps (GDI32.@)
4857 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
4859 static int hinting
= -1;
4863 hinting
= is_hinting_enabled();
4864 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
4867 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
4868 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
4869 lprs
->nLanguageID
= 0;
4873 /*************************************************************************
4874 * Kerning support for TrueType fonts
4876 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4878 struct TT_kern_table
4884 struct TT_kern_subtable
4893 USHORT horizontal
: 1;
4895 USHORT cross_stream
: 1;
4896 USHORT override
: 1;
4897 USHORT reserved1
: 4;
4903 struct TT_format0_kern_subtable
4907 USHORT entrySelector
;
4918 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
4919 const struct TT_format0_kern_subtable
*tt_f0_ks
,
4920 const USHORT
*glyph_to_char
,
4921 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
4924 const struct TT_kern_pair
*tt_kern_pair
;
4926 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
4928 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
4930 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4931 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
4932 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
4934 if (!kern_pair
|| !cPairs
)
4937 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
4939 nPairs
= min(nPairs
, cPairs
);
4941 for (i
= 0; i
< nPairs
; i
++)
4943 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
4944 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
4945 /* this algorithm appears to better match what Windows does */
4946 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
4947 if (kern_pair
->iKernAmount
< 0)
4949 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
4950 kern_pair
->iKernAmount
-= font
->ppem
;
4952 else if (kern_pair
->iKernAmount
> 0)
4954 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
4955 kern_pair
->iKernAmount
+= font
->ppem
;
4957 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
4959 TRACE("left %u right %u value %d\n",
4960 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
4964 TRACE("copied %u entries\n", nPairs
);
4968 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
4972 const struct TT_kern_table
*tt_kern_table
;
4973 const struct TT_kern_subtable
*tt_kern_subtable
;
4975 USHORT
*glyph_to_char
;
4977 if (font
->total_kern_pairs
!= (DWORD
)-1)
4979 if (cPairs
&& kern_pair
)
4981 cPairs
= min(cPairs
, font
->total_kern_pairs
);
4982 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
4985 return font
->total_kern_pairs
;
4988 font
->total_kern_pairs
= 0;
4990 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
4992 if (length
== GDI_ERROR
)
4994 TRACE("no kerning data in the font\n");
4998 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
5001 WARN("Out of memory\n");
5005 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
5007 /* build a glyph index to char code map */
5008 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
5011 WARN("Out of memory allocating a glyph index to char code map\n");
5012 HeapFree(GetProcessHeap(), 0, buf
);
5016 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5022 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
5024 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5025 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
5029 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5031 /* FIXME: This doesn't match what Windows does: it does some fancy
5032 * things with duplicate glyph index to char code mappings, while
5033 * we just avoid overriding existing entries.
5035 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
5036 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
5038 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
5045 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
5046 for (n
= 0; n
<= 65535; n
++)
5047 glyph_to_char
[n
] = (USHORT
)n
;
5050 tt_kern_table
= buf
;
5051 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
5052 TRACE("version %u, nTables %u\n",
5053 GET_BE_WORD(tt_kern_table
->version
), nTables
);
5055 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
5057 for (i
= 0; i
< nTables
; i
++)
5059 struct TT_kern_subtable tt_kern_subtable_copy
;
5061 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
5062 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
5063 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
5065 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5066 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
5067 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
5069 /* According to the TrueType specification this is the only format
5070 * that will be properly interpreted by Windows and OS/2
5072 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
5074 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
5076 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5077 glyph_to_char
, NULL
, 0);
5078 font
->total_kern_pairs
+= new_chunk
;
5080 if (!font
->kern_pairs
)
5081 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
5082 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5084 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
5085 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5087 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5088 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
5091 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
5093 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
5096 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
5097 HeapFree(GetProcessHeap(), 0, buf
);
5099 if (cPairs
&& kern_pair
)
5101 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5102 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5105 return font
->total_kern_pairs
;
5108 #else /* HAVE_FREETYPE */
5110 /*************************************************************************/
5112 BOOL
WineEngInit(void)
5116 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
5120 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
5125 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5130 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
5131 LPWORD pgi
, DWORD flags
)
5136 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
5137 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5140 ERR("called but we don't have FreeType\n");
5144 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5146 ERR("called but we don't have FreeType\n");
5150 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5151 OUTLINETEXTMETRICW
*potm
)
5153 ERR("called but we don't have FreeType\n");
5157 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5160 ERR("called but we don't have FreeType\n");
5164 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5167 ERR("called but we don't have FreeType\n");
5171 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5174 ERR("called but we don't have FreeType\n");
5178 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5179 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5181 ERR("called but we don't have FreeType\n");
5185 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5186 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5188 ERR("called but we don't have FreeType\n");
5192 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5195 ERR("called but we don't have FreeType\n");
5199 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5201 ERR("called but we don't have FreeType\n");
5205 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5211 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5217 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
5223 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5226 return DEFAULT_CHARSET
;
5229 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5234 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5236 FIXME("(%p, %p): stub\n", font
, glyphset
);
5240 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5245 /*************************************************************************
5246 * GetRasterizerCaps (GDI32.@)
5248 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5250 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5252 lprs
->nLanguageID
= 0;
5256 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5258 ERR("called but we don't have FreeType\n");
5262 #endif /* HAVE_FREETYPE */