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
;
248 NEWTEXTMETRICEXW ntm
;
252 typedef struct tagFace
{
257 DWORD font_data_size
;
262 FONTSIGNATURE fs_links
;
263 DWORD ntmFlags
; /* Only some bits stored here. Others are computed on the fly */
264 FT_Fixed font_version
;
266 Bitmap_Size size
; /* set if face is a bitmap */
267 BOOL external
; /* TRUE if we should manually add this font to the registry */
268 struct tagFamily
*family
;
269 /* Cached data for Enum */
270 struct enum_data
*cached_enum_data
;
273 typedef struct tagFamily
{
275 const WCHAR
*FamilyName
;
281 INT adv
; /* These three hold to widths of the unrotated chars */
299 typedef struct tagHFONTLIST
{
313 struct font_mapping
*mapping
;
324 struct list hfontlist
;
330 OUTLINETEXTMETRICW
*potm
;
332 DWORD total_kern_pairs
;
333 KERNINGPAIR
*kern_pairs
;
336 struct list child_fonts
;
341 const WCHAR
*font_name
;
345 #define GM_BLOCK_SIZE 128
346 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
348 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
349 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
350 #define UNUSED_CACHE_SIZE 10
351 static struct list child_font_list
= LIST_INIT(child_font_list
);
352 static struct list system_links
= LIST_INIT(system_links
);
354 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
356 static struct list font_list
= LIST_INIT(font_list
);
358 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
359 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
360 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
362 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
364 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
365 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
366 'W','i','n','d','o','w','s','\\',
367 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
368 'F','o','n','t','s','\0'};
370 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
371 'W','i','n','d','o','w','s',' ','N','T','\\',
372 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
373 'F','o','n','t','s','\0'};
375 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
376 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
377 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
378 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
380 static const WCHAR
* const SystemFontValues
[4] = {
387 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
388 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
390 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
391 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
392 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
393 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
394 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
395 'E','u','r','o','p','e','a','n','\0'};
396 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
397 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
398 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
399 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
400 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
401 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
402 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
403 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
404 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
405 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
406 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
407 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
409 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
419 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
427 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
436 typedef struct tagFontSubst
{
452 static struct list mappings_list
= LIST_INIT( mappings_list
);
454 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
456 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
458 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
460 /****************************************
461 * Notes on .fon files
463 * The fonts System, FixedSys and Terminal are special. There are typically multiple
464 * versions installed for different resolutions and codepages. Windows stores which one to use
465 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
467 * FIXEDFON.FON FixedSys
469 * OEMFONT.FON Terminal
470 * LogPixels Current dpi set by the display control panel applet
471 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
472 * also has a LogPixels value that appears to mirror this)
474 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
475 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
476 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
477 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
478 * so that makes sense.
480 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
481 * to be mapped into the registry on Windows 2000 at least).
484 * ega80woa.fon=ega80850.fon
485 * ega40woa.fon=ega40850.fon
486 * cga80woa.fon=cga80850.fon
487 * cga40woa.fon=cga40850.fon
490 #ifdef HAVE_CARBON_CARBON_H
491 static char *find_cache_dir(void)
495 static char cached_path
[MAX_PATH
];
496 static const char *wine
= "/Wine", *fonts
= "/Fonts";
498 if(*cached_path
) return cached_path
;
500 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
503 WARN("can't create cached data folder\n");
506 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
509 WARN("can't create cached data path\n");
513 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
515 ERR("Could not create full path\n");
519 strcat(cached_path
, wine
);
521 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
523 WARN("Couldn't mkdir %s\n", cached_path
);
527 strcat(cached_path
, fonts
);
528 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
530 WARN("Couldn't mkdir %s\n", cached_path
);
537 /******************************************************************
540 * Extracts individual TrueType font files from a Mac suitcase font
541 * and saves them into the user's caches directory (see
543 * Returns a NULL terminated array of filenames.
545 * We do this because they are apps that try to read ttf files
546 * themselves and they don't like Mac suitcase files.
548 static char **expand_mac_font(const char *path
)
555 const char *filename
;
559 unsigned int size
, max_size
;
562 TRACE("path %s\n", path
);
564 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
567 WARN("failed to get ref\n");
571 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
574 TRACE("no data fork, so trying resource fork\n");
575 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
578 TRACE("unable to open resource fork\n");
585 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
588 CloseResFile(res_ref
);
592 out_dir
= find_cache_dir();
594 filename
= strrchr(path
, '/');
595 if(!filename
) filename
= path
;
598 /* output filename has the form out_dir/filename_%04x.ttf */
599 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
606 unsigned short *num_faces_ptr
, num_faces
, face
;
609 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
611 fond
= Get1IndResource(fond_res
, idx
);
613 TRACE("got fond resource %d\n", idx
);
616 fam_rec
= *(FamRec
**)fond
;
617 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
618 num_faces
= GET_BE_WORD(*num_faces_ptr
);
620 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
621 TRACE("num faces %04x\n", num_faces
);
622 for(face
= 0; face
< num_faces
; face
++, assoc
++)
625 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
626 unsigned short size
, font_id
;
629 size
= GET_BE_WORD(assoc
->fontSize
);
630 font_id
= GET_BE_WORD(assoc
->fontID
);
633 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
637 TRACE("trying to load sfnt id %04x\n", font_id
);
638 sfnt
= GetResource(sfnt_res
, font_id
);
641 TRACE("can't get sfnt resource %04x\n", font_id
);
645 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
650 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
652 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
653 if(fd
!= -1 || errno
== EEXIST
)
657 unsigned char *sfnt_data
;
660 sfnt_data
= *(unsigned char**)sfnt
;
661 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
665 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
668 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
670 ret
.array
[ret
.size
++] = output
;
674 WARN("unable to create %s\n", output
);
675 HeapFree(GetProcessHeap(), 0, output
);
678 ReleaseResource(sfnt
);
681 ReleaseResource(fond
);
684 CloseResFile(res_ref
);
689 #endif /* HAVE_CARBON_CARBON_H */
691 static inline BOOL
is_win9x(void)
693 return GetVersion() & 0x80000000;
696 This function builds an FT_Fixed from a float. It puts the integer part
697 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
698 It fails if the integer part of the float number is greater than SHORT_MAX.
700 static inline FT_Fixed
FT_FixedFromFloat(float f
)
703 unsigned short fract
= (f
- value
) * 0xFFFF;
704 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
708 This function builds an FT_Fixed from a FIXED. It simply put f.value
709 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
711 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
713 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
717 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
722 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
723 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
725 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
726 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
728 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
730 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
732 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
736 file
= strrchr(face
->file
, '/');
741 if(!strcasecmp(file
, file_nameA
))
743 HeapFree(GetProcessHeap(), 0, file_nameA
);
748 HeapFree(GetProcessHeap(), 0, file_nameA
);
752 static Family
*find_family_from_name(const WCHAR
*name
)
756 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
758 if(!strcmpiW(family
->FamilyName
, name
))
765 static void DumpSubstList(void)
769 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
771 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
772 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
773 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
775 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
776 debugstr_w(psub
->to
.name
));
781 static LPWSTR
strdupW(LPCWSTR p
)
784 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
785 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
790 static LPSTR
strdupA(LPCSTR p
)
793 DWORD len
= (strlen(p
) + 1);
794 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
799 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
804 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
806 if(!strcmpiW(element
->from
.name
, from_name
) &&
807 (element
->from
.charset
== from_charset
||
808 element
->from
.charset
== -1))
815 #define ADD_FONT_SUBST_FORCE 1
817 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
819 FontSubst
*from_exist
, *to_exist
;
821 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
823 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
825 list_remove(&from_exist
->entry
);
826 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
827 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
828 HeapFree(GetProcessHeap(), 0, from_exist
);
834 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
838 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
839 subst
->to
.name
= strdupW(to_exist
->to
.name
);
842 list_add_tail(subst_list
, &subst
->entry
);
847 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
848 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
849 HeapFree(GetProcessHeap(), 0, subst
);
853 static void split_subst_info(NameCs
*nc
, LPSTR str
)
855 CHAR
*p
= strrchr(str
, ',');
860 nc
->charset
= strtol(p
+1, NULL
, 10);
863 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
864 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
865 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
868 static void LoadSubstList(void)
872 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
876 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
877 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
878 &hkey
) == ERROR_SUCCESS
) {
880 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
881 &valuelen
, &datalen
, NULL
, NULL
);
883 valuelen
++; /* returned value doesn't include room for '\0' */
884 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
885 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
889 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
890 &dlen
) == ERROR_SUCCESS
) {
891 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
893 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
894 split_subst_info(&psub
->from
, value
);
895 split_subst_info(&psub
->to
, data
);
897 /* Win 2000 doesn't allow mapping between different charsets
898 or mapping of DEFAULT_CHARSET */
899 if((psub
->to
.charset
!= psub
->from
.charset
) ||
900 psub
->to
.charset
== DEFAULT_CHARSET
) {
901 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
902 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
903 HeapFree(GetProcessHeap(), 0, psub
);
905 add_font_subst(&font_subst_list
, psub
, 0);
907 /* reset dlen and vlen */
911 HeapFree(GetProcessHeap(), 0, data
);
912 HeapFree(GetProcessHeap(), 0, value
);
917 static WCHAR
*get_familyname(FT_Face ft_face
)
919 WCHAR
*family
= NULL
;
921 FT_UInt num_names
, name_index
, i
;
923 if(FT_IS_SFNT(ft_face
))
925 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
927 for(name_index
= 0; name_index
< num_names
; name_index
++)
929 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
931 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
932 (name
.language_id
== GetUserDefaultLCID()) &&
933 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
934 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
936 /* String is not nul terminated and string_len is a byte length. */
937 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
938 for(i
= 0; i
< name
.string_len
/ 2; i
++)
940 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
941 family
[i
] = GET_BE_WORD(*tmp
);
945 TRACE("Got localised name %s\n", debugstr_w(family
));
956 /*****************************************************************
959 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
960 * of FreeType that don't export this function.
963 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
968 /* If the FT_Load_Sfnt_Table function is there we'll use it */
969 if(pFT_Load_Sfnt_Table
)
971 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
973 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
974 else /* Do it the hard way */
976 TT_Face tt_face
= (TT_Face
) ft_face
;
977 SFNT_Interface
*sfnt
;
978 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
981 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
985 /* A field was added in the middle of the structure in 2.1.x */
986 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
988 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
996 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
997 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
998 "Please upgrade your freetype library.\n");
1001 err
= FT_Err_Unimplemented_Feature
;
1008 #define ADDFONT_EXTERNAL_FONT 0x01
1009 #define ADDFONT_FORCE_BITMAP 0x02
1010 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1014 TT_Header
*pHeader
= NULL
;
1015 WCHAR
*english_family
, *localised_family
, *StyleW
;
1019 struct list
*family_elem_ptr
, *face_elem_ptr
;
1021 FT_Long face_index
= 0, num_faces
;
1022 #ifdef HAVE_FREETYPE_FTWINFNT_H
1023 FT_WinFNT_HeaderRec winfnt_header
;
1025 int i
, bitmap_num
, internal_leading
;
1028 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1029 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1031 #ifdef HAVE_CARBON_CARBON_H
1032 if(file
&& !fake_family
)
1034 char **mac_list
= expand_mac_font(file
);
1037 BOOL had_one
= FALSE
;
1039 for(cursor
= mac_list
; *cursor
; cursor
++)
1042 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1043 HeapFree(GetProcessHeap(), 0, *cursor
);
1045 HeapFree(GetProcessHeap(), 0, mac_list
);
1050 #endif /* HAVE_CARBON_CARBON_H */
1053 char *family_name
= fake_family
;
1057 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1058 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1061 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1062 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1066 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1070 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*/
1071 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1072 pFT_Done_Face(ft_face
);
1076 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1077 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1078 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1079 pFT_Done_Face(ft_face
);
1083 if(FT_IS_SFNT(ft_face
))
1085 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1086 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1087 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1089 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1090 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1091 pFT_Done_Face(ft_face
);
1095 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1096 we don't want to load these. */
1097 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1101 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1103 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1104 pFT_Done_Face(ft_face
);
1110 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1111 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1112 pFT_Done_Face(ft_face
);
1118 localised_family
= get_familyname(ft_face
);
1119 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1121 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1122 HeapFree(GetProcessHeap(), 0, localised_family
);
1123 num_faces
= ft_face
->num_faces
;
1124 pFT_Done_Face(ft_face
);
1127 HeapFree(GetProcessHeap(), 0, localised_family
);
1131 family_name
= ft_face
->family_name
;
1135 My_FT_Bitmap_Size
*size
= NULL
;
1138 if(!FT_IS_SCALABLE(ft_face
))
1139 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1141 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1142 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1143 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1145 localised_family
= NULL
;
1147 localised_family
= get_familyname(ft_face
);
1148 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1149 HeapFree(GetProcessHeap(), 0, localised_family
);
1150 localised_family
= NULL
;
1155 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1156 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1157 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1162 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1163 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1164 list_init(&family
->faces
);
1165 list_add_tail(&font_list
, &family
->entry
);
1167 if(localised_family
) {
1168 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1169 subst
->from
.name
= strdupW(english_family
);
1170 subst
->from
.charset
= -1;
1171 subst
->to
.name
= strdupW(localised_family
);
1172 subst
->to
.charset
= -1;
1173 add_font_subst(&font_subst_list
, subst
, 0);
1176 HeapFree(GetProcessHeap(), 0, localised_family
);
1177 HeapFree(GetProcessHeap(), 0, english_family
);
1179 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1180 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1181 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1183 internal_leading
= 0;
1184 memset(&fs
, 0, sizeof(fs
));
1186 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1188 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1189 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1190 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1191 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1192 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1193 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1194 if(pOS2
->version
== 0) {
1197 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1198 fs
.fsCsb
[0] |= FS_LATIN1
;
1200 fs
.fsCsb
[0] |= FS_SYMBOL
;
1203 #ifdef HAVE_FREETYPE_FTWINFNT_H
1204 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1206 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1207 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1208 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1209 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
1210 internal_leading
= winfnt_header
.internal_leading
;
1214 face_elem_ptr
= list_head(&family
->faces
);
1215 while(face_elem_ptr
) {
1216 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1217 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1218 if(!strcmpW(face
->StyleName
, StyleW
) &&
1219 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1220 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1221 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1222 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1225 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1226 HeapFree(GetProcessHeap(), 0, StyleW
);
1227 pFT_Done_Face(ft_face
);
1230 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1231 TRACE("Original font is newer so skipping this one\n");
1232 HeapFree(GetProcessHeap(), 0, StyleW
);
1233 pFT_Done_Face(ft_face
);
1236 TRACE("Replacing original with this one\n");
1237 list_remove(&face
->entry
);
1238 HeapFree(GetProcessHeap(), 0, face
->file
);
1239 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1240 HeapFree(GetProcessHeap(), 0, face
);
1245 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1246 face
->cached_enum_data
= NULL
;
1247 list_add_tail(&family
->faces
, &face
->entry
);
1248 face
->StyleName
= StyleW
;
1251 face
->file
= strdupA(file
);
1252 face
->font_data_ptr
= NULL
;
1253 face
->font_data_size
= 0;
1258 face
->font_data_ptr
= font_data_ptr
;
1259 face
->font_data_size
= font_data_size
;
1261 face
->face_index
= face_index
;
1262 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
1263 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
1264 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1265 face
->family
= family
;
1266 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1267 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
1268 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1270 if(FT_IS_SCALABLE(ft_face
)) {
1271 memset(&face
->size
, 0, sizeof(face
->size
));
1272 face
->scalable
= TRUE
;
1274 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1275 size
->height
, size
->width
, size
->size
>> 6,
1276 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1277 face
->size
.height
= size
->height
;
1278 face
->size
.width
= size
->width
;
1279 face
->size
.size
= size
->size
;
1280 face
->size
.x_ppem
= size
->x_ppem
;
1281 face
->size
.y_ppem
= size
->y_ppem
;
1282 face
->size
.internal_leading
= internal_leading
;
1283 face
->scalable
= FALSE
;
1286 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1288 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1290 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1291 face
->ntmFlags
= NTM_PS_OPENTYPE
;
1296 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1297 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1298 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1299 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1302 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1303 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1304 switch(ft_face
->charmaps
[i
]->encoding
) {
1305 case FT_ENCODING_UNICODE
:
1306 case FT_ENCODING_APPLE_ROMAN
:
1307 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1309 case FT_ENCODING_MS_SYMBOL
:
1310 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1318 if (!(face
->fs
.fsCsb
[0] & FS_SYMBOL
))
1319 have_installed_roman_font
= TRUE
;
1320 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1322 num_faces
= ft_face
->num_faces
;
1323 pFT_Done_Face(ft_face
);
1324 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1325 debugstr_w(StyleW
));
1326 } while(num_faces
> ++face_index
);
1330 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1332 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1335 static void DumpFontList(void)
1339 struct list
*family_elem_ptr
, *face_elem_ptr
;
1341 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1342 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1343 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1344 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1345 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1346 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1348 TRACE(" %d", face
->size
.height
);
1355 /***********************************************************
1356 * The replacement list is a way to map an entire font
1357 * family onto another family. For example adding
1359 * [HKCU\Software\Wine\Fonts\Replacements]
1360 * "Wingdings"="Winedings"
1362 * would enumerate the Winedings font both as Winedings and
1363 * Wingdings. However if a real Wingdings font is present the
1364 * replacement does not take place.
1367 static void LoadReplaceList(void)
1370 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1375 struct list
*family_elem_ptr
, *face_elem_ptr
;
1378 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1379 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1381 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1382 &valuelen
, &datalen
, NULL
, NULL
);
1384 valuelen
++; /* returned value doesn't include room for '\0' */
1385 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1386 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1390 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1391 &dlen
) == ERROR_SUCCESS
) {
1392 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1393 /* "NewName"="Oldname" */
1394 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1396 /* Find the old family and hence all of the font files
1398 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1399 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1400 if(!strcmpiW(family
->FamilyName
, data
)) {
1401 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1402 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1403 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1404 debugstr_w(face
->StyleName
), familyA
);
1405 /* Now add a new entry with the new family name */
1406 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1411 /* reset dlen and vlen */
1415 HeapFree(GetProcessHeap(), 0, data
);
1416 HeapFree(GetProcessHeap(), 0, value
);
1421 /*************************************************************
1424 static BOOL
init_system_links(void)
1426 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1427 'W','i','n','d','o','w','s',' ','N','T','\\',
1428 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1429 'S','y','s','t','e','m','L','i','n','k',0};
1432 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1433 WCHAR
*value
, *data
;
1434 WCHAR
*entry
, *next
;
1435 SYSTEM_LINKS
*font_link
, *system_font_link
;
1436 CHILD_FONT
*child_font
;
1437 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1438 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1439 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1445 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1447 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1448 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1449 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1450 val_len
= max_val
+ 1;
1451 data_len
= max_data
;
1453 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1455 TRACE("%s:\n", debugstr_w(value
));
1457 memset(&fs
, 0, sizeof(fs
));
1458 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1459 psub
= get_font_subst(&font_subst_list
, value
, -1);
1460 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1461 list_init(&font_link
->links
);
1462 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1465 CHILD_FONT
*child_font
;
1467 TRACE("\t%s\n", debugstr_w(entry
));
1469 next
= entry
+ strlenW(entry
) + 1;
1471 face_name
= strchrW(entry
, ',');
1475 while(isspaceW(*face_name
))
1478 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1480 face_name
= psub
->to
.name
;
1482 face
= find_face_from_filename(entry
, face_name
);
1485 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1489 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1490 child_font
->face
= face
;
1491 child_font
->font
= NULL
;
1492 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1493 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1494 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1495 list_add_tail(&font_link
->links
, &child_font
->entry
);
1497 family
= find_family_from_name(font_link
->font_name
);
1500 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1502 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
1505 list_add_tail(&system_links
, &font_link
->entry
);
1506 val_len
= max_val
+ 1;
1507 data_len
= max_data
;
1510 HeapFree(GetProcessHeap(), 0, value
);
1511 HeapFree(GetProcessHeap(), 0, data
);
1515 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1518 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1519 system_font_link
->font_name
= strdupW(System
);
1520 list_init(&system_font_link
->links
);
1522 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1525 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1526 child_font
->face
= face
;
1527 child_font
->font
= NULL
;
1528 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1529 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1531 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1533 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1535 CHILD_FONT
*font_link_entry
;
1536 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1538 CHILD_FONT
*new_child
;
1539 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1540 new_child
->face
= font_link_entry
->face
;
1541 new_child
->font
= NULL
;
1542 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1547 list_add_tail(&system_links
, &system_font_link
->entry
);
1551 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1554 struct dirent
*dent
;
1555 char path
[MAX_PATH
];
1557 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1559 dir
= opendir(dirname
);
1561 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1564 while((dent
= readdir(dir
)) != NULL
) {
1565 struct stat statbuf
;
1567 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1570 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1572 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1574 if(stat(path
, &statbuf
) == -1)
1576 WARN("Can't stat %s\n", debugstr_a(path
));
1579 if(S_ISDIR(statbuf
.st_mode
))
1580 ReadFontDir(path
, external_fonts
);
1582 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1588 static void load_fontconfig_fonts(void)
1590 #ifdef SONAME_LIBFONTCONFIG
1591 void *fc_handle
= NULL
;
1600 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1602 TRACE("Wine cannot find the fontconfig library (%s).\n",
1603 SONAME_LIBFONTCONFIG
);
1606 #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;}
1607 LOAD_FUNCPTR(FcConfigGetCurrent
);
1608 LOAD_FUNCPTR(FcFontList
);
1609 LOAD_FUNCPTR(FcFontSetDestroy
);
1610 LOAD_FUNCPTR(FcInit
);
1611 LOAD_FUNCPTR(FcObjectSetAdd
);
1612 LOAD_FUNCPTR(FcObjectSetCreate
);
1613 LOAD_FUNCPTR(FcObjectSetDestroy
);
1614 LOAD_FUNCPTR(FcPatternCreate
);
1615 LOAD_FUNCPTR(FcPatternDestroy
);
1616 LOAD_FUNCPTR(FcPatternGetBool
);
1617 LOAD_FUNCPTR(FcPatternGetString
);
1620 if(!pFcInit()) return;
1622 config
= pFcConfigGetCurrent();
1623 pat
= pFcPatternCreate();
1624 os
= pFcObjectSetCreate();
1625 pFcObjectSetAdd(os
, FC_FILE
);
1626 pFcObjectSetAdd(os
, FC_SCALABLE
);
1627 fontset
= pFcFontList(config
, pat
, os
);
1628 if(!fontset
) return;
1629 for(i
= 0; i
< fontset
->nfont
; i
++) {
1632 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1634 TRACE("fontconfig: %s\n", file
);
1636 /* We're just interested in OT/TT fonts for now, so this hack just
1637 picks up the scalable fonts without extensions .pf[ab] to save time
1638 loading every other font */
1640 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1642 TRACE("not scalable\n");
1646 len
= strlen( file
);
1647 if(len
< 4) continue;
1648 ext
= &file
[ len
- 3 ];
1649 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1650 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1652 pFcFontSetDestroy(fontset
);
1653 pFcObjectSetDestroy(os
);
1654 pFcPatternDestroy(pat
);
1660 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1663 const char *data_dir
= wine_get_data_dir();
1665 if (!data_dir
) data_dir
= wine_get_build_dir();
1672 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1674 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1676 strcpy(unix_name
, data_dir
);
1677 strcat(unix_name
, "/fonts/");
1679 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1681 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1682 HeapFree(GetProcessHeap(), 0, unix_name
);
1687 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1689 static const WCHAR slashW
[] = {'\\','\0'};
1691 WCHAR windowsdir
[MAX_PATH
];
1694 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1695 strcatW(windowsdir
, fontsW
);
1696 strcatW(windowsdir
, slashW
);
1697 strcatW(windowsdir
, file
);
1698 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1699 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1700 HeapFree(GetProcessHeap(), 0, unixname
);
1705 static void load_system_fonts(void)
1708 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1709 const WCHAR
* const *value
;
1711 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1714 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1715 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1716 strcatW(windowsdir
, fontsW
);
1717 for(value
= SystemFontValues
; *value
; value
++) {
1718 dlen
= sizeof(data
);
1719 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1723 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1724 if((unixname
= wine_get_unix_file_name(pathW
))) {
1725 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1726 HeapFree(GetProcessHeap(), 0, unixname
);
1729 load_font_from_data_dir(data
);
1736 /*************************************************************
1738 * This adds registry entries for any externally loaded fonts
1739 * (fonts from fontconfig or FontDirs). It also deletes entries
1740 * of no longer existing fonts.
1743 static void update_reg_entries(void)
1745 HKEY winkey
= 0, externalkey
= 0;
1748 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
1751 struct list
*family_elem_ptr
, *face_elem_ptr
;
1753 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1754 static const WCHAR spaceW
[] = {' ', '\0'};
1757 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1758 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
1759 ERR("Can't create Windows font reg key\n");
1762 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1763 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
1764 ERR("Can't create external font reg key\n");
1768 /* Delete all external fonts added last time */
1770 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1771 &valuelen
, &datalen
, NULL
, NULL
);
1772 valuelen
++; /* returned value doesn't include room for '\0' */
1773 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1774 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1776 dlen
= datalen
* sizeof(WCHAR
);
1779 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1780 &dlen
) == ERROR_SUCCESS
) {
1782 RegDeleteValueW(winkey
, valueW
);
1783 /* reset dlen and vlen */
1787 HeapFree(GetProcessHeap(), 0, data
);
1788 HeapFree(GetProcessHeap(), 0, valueW
);
1790 /* Delete the old external fonts key */
1791 RegCloseKey(externalkey
);
1793 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1795 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1796 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1797 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
1798 ERR("Can't create external font reg key\n");
1802 /* enumerate the fonts and add external ones to the two keys */
1804 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1805 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1806 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1807 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1808 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1809 if(!face
->external
) continue;
1811 if(strcmpiW(face
->StyleName
, RegularW
))
1812 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1813 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1814 strcpyW(valueW
, family
->FamilyName
);
1815 if(len
!= len_fam
) {
1816 strcatW(valueW
, spaceW
);
1817 strcatW(valueW
, face
->StyleName
);
1819 strcatW(valueW
, TrueType
);
1820 if((path
= strrchr(face
->file
, '/')) == NULL
)
1824 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1826 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1827 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1828 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1829 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1831 HeapFree(GetProcessHeap(), 0, file
);
1832 HeapFree(GetProcessHeap(), 0, valueW
);
1837 RegCloseKey(externalkey
);
1839 RegCloseKey(winkey
);
1844 /*************************************************************
1845 * WineEngAddFontResourceEx
1848 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1851 if (ft_handle
) /* do it only if we have freetype up and running */
1856 FIXME("Ignoring flags %x\n", flags
);
1858 if((unixname
= wine_get_unix_file_name(file
)))
1860 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1861 HeapFree(GetProcessHeap(), 0, unixname
);
1863 if (!ret
&& !strchrW(file
, '\\')) {
1864 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
1865 ret
= load_font_from_winfonts_dir(file
);
1867 /* Try in datadir/fonts (or builddir/fonts),
1868 * needed for Magic the Gathering Online
1870 ret
= load_font_from_data_dir(file
);
1877 /*************************************************************
1878 * WineEngAddFontMemResourceEx
1881 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
1883 if (ft_handle
) /* do it only if we have freetype up and running */
1885 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
1887 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
1888 memcpy(pFontCopy
, pbFont
, cbFont
);
1890 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1894 TRACE("AddFontToList failed\n");
1895 HeapFree(GetProcessHeap(), 0, pFontCopy
);
1898 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1899 * For now return something unique but quite random
1901 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
1902 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
1909 /*************************************************************
1910 * WineEngRemoveFontResourceEx
1913 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1919 static const struct nls_update_font_list
1921 UINT ansi_cp
, oem_cp
;
1922 const char *oem
, *fixed
, *system
;
1923 const char *courier
, *serif
, *small
, *sserif
;
1924 /* these are for font substitute */
1925 const char *shelldlg
, *tmsrmn
;
1926 } nls_update_font_list
[] =
1928 /* Latin 1 (United States) */
1929 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1930 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1931 "Tahoma","Times New Roman",
1933 /* Latin 1 (Multilingual) */
1934 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1935 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1936 "Tahoma","Times New Roman", /* FIXME unverified */
1938 /* Eastern Europe */
1939 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1940 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1941 "Tahoma","Times New Roman", /* FIXME unverified */
1944 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1945 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1946 "Tahoma","Times New Roman", /* FIXME unverified */
1949 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1950 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1951 "Tahoma","Times New Roman", /* FIXME unverified */
1954 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1955 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1956 "Tahoma","Times New Roman", /* FIXME unverified */
1959 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1960 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1961 "Tahoma","Times New Roman", /* FIXME unverified */
1964 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1965 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1966 "Tahoma","Times New Roman", /* FIXME unverified */
1969 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1970 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1971 "Tahoma","Times New Roman", /* FIXME unverified */
1974 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1975 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1976 "Tahoma","Times New Roman", /* FIXME unverified */
1979 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1980 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1981 "Tahoma","Times New Roman", /* FIXME unverified */
1984 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1985 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1986 "MS UI Gothic","MS Serif",
1988 /* Chinese Simplified */
1989 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1990 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1991 "Tahoma", "Times New Roman", /* FIXME unverified */
1994 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1995 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1998 /* Chinese Traditional */
1999 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2000 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2001 "PMingLiU", "MingLiU",
2005 static inline HKEY
create_fonts_NT_registry_key(void)
2009 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2010 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2014 static inline HKEY
create_fonts_9x_registry_key(void)
2018 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2019 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2023 static inline HKEY
create_config_fonts_registry_key(void)
2027 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2028 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2032 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2034 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2035 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2036 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2037 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2040 static void update_font_info(void)
2042 char buf
[40], cpbuf
[40];
2045 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2047 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2050 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2051 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2052 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2053 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2054 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2057 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2059 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2064 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2066 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2068 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2071 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2073 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2074 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2078 hkey
= create_config_fonts_registry_key();
2079 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2080 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2081 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2084 hkey
= create_fonts_NT_registry_key();
2085 add_font_list(hkey
, &nls_update_font_list
[i
]);
2088 hkey
= create_fonts_9x_registry_key();
2089 add_font_list(hkey
, &nls_update_font_list
[i
]);
2092 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2094 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2095 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2096 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2097 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2103 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2106 /*************************************************************
2109 * Initialize FreeType library and create a list of available faces
2111 BOOL
WineEngInit(void)
2113 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2114 static const WCHAR pathW
[] = {'P','a','t','h',0};
2116 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2118 WCHAR windowsdir
[MAX_PATH
];
2121 const char *data_dir
;
2125 /* update locale dependent font info in registry */
2128 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2131 "Wine cannot find the FreeType font library. To enable Wine to\n"
2132 "use TrueType fonts please install a version of FreeType greater than\n"
2133 "or equal to 2.0.5.\n"
2134 "http://www.freetype.org\n");
2138 #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;}
2140 LOAD_FUNCPTR(FT_Vector_Unit
)
2141 LOAD_FUNCPTR(FT_Done_Face
)
2142 LOAD_FUNCPTR(FT_Get_Char_Index
)
2143 LOAD_FUNCPTR(FT_Get_Module
)
2144 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2145 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2146 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2147 LOAD_FUNCPTR(FT_Init_FreeType
)
2148 LOAD_FUNCPTR(FT_Load_Glyph
)
2149 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2150 LOAD_FUNCPTR(FT_MulFix
)
2151 LOAD_FUNCPTR(FT_New_Face
)
2152 LOAD_FUNCPTR(FT_New_Memory_Face
)
2153 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2154 LOAD_FUNCPTR(FT_Outline_Transform
)
2155 LOAD_FUNCPTR(FT_Outline_Translate
)
2156 LOAD_FUNCPTR(FT_Select_Charmap
)
2157 LOAD_FUNCPTR(FT_Set_Charmap
)
2158 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2159 LOAD_FUNCPTR(FT_Vector_Transform
)
2162 /* Don't warn if this one is missing */
2163 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2164 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2165 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2166 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2167 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2168 #ifdef HAVE_FREETYPE_FTWINFNT_H
2169 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2171 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2172 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2173 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2174 <= 2.0.3 has FT_Sqrt64 */
2178 if(pFT_Init_FreeType(&library
) != 0) {
2179 ERR("Can't init FreeType library\n");
2180 wine_dlclose(ft_handle
, NULL
, 0);
2184 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
2185 if (pFT_Library_Version
)
2187 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2189 if (FT_Version
.major
<=0)
2195 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2196 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2197 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2198 ((FT_Version
.patch
) & 0x0000ff);
2200 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2201 ERR("Failed to create font mutex\n");
2204 WaitForSingleObject(font_mutex
, INFINITE
);
2206 /* load the system bitmap fonts */
2207 load_system_fonts();
2209 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2210 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2211 strcatW(windowsdir
, fontsW
);
2212 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2214 ReadFontDir(unixname
, FALSE
);
2215 HeapFree(GetProcessHeap(), 0, unixname
);
2218 /* load the system truetype fonts */
2219 data_dir
= wine_get_data_dir();
2220 if (!data_dir
) data_dir
= wine_get_build_dir();
2221 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2222 strcpy(unixname
, data_dir
);
2223 strcat(unixname
, "/fonts/");
2224 ReadFontDir(unixname
, TRUE
);
2225 HeapFree(GetProcessHeap(), 0, unixname
);
2228 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2229 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2230 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2232 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2233 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2234 &hkey
) == ERROR_SUCCESS
) {
2236 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2237 &valuelen
, &datalen
, NULL
, NULL
);
2239 valuelen
++; /* returned value doesn't include room for '\0' */
2240 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2241 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2244 dlen
= datalen
* sizeof(WCHAR
);
2246 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2247 &dlen
) == ERROR_SUCCESS
) {
2248 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2250 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2252 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2253 HeapFree(GetProcessHeap(), 0, unixname
);
2256 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2258 WCHAR pathW
[MAX_PATH
];
2259 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2262 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2263 if((unixname
= wine_get_unix_file_name(pathW
)))
2265 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2266 HeapFree(GetProcessHeap(), 0, unixname
);
2269 load_font_from_data_dir(data
);
2271 /* reset dlen and vlen */
2276 HeapFree(GetProcessHeap(), 0, data
);
2277 HeapFree(GetProcessHeap(), 0, valueW
);
2281 load_fontconfig_fonts();
2283 /* then look in any directories that we've specified in the config file */
2284 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2285 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2291 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2293 len
+= sizeof(WCHAR
);
2294 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2295 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2297 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2298 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2299 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2300 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2304 LPSTR next
= strchr( ptr
, ':' );
2305 if (next
) *next
++ = 0;
2306 ReadFontDir( ptr
, TRUE
);
2309 HeapFree( GetProcessHeap(), 0, valueA
);
2311 HeapFree( GetProcessHeap(), 0, valueW
);
2320 update_reg_entries();
2322 init_system_links();
2324 ReleaseMutex(font_mutex
);
2328 "Wine cannot find certain functions that it needs inside the FreeType\n"
2329 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2330 "FreeType to at least version 2.0.5.\n"
2331 "http://www.freetype.org\n");
2332 wine_dlclose(ft_handle
, NULL
, 0);
2338 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2341 TT_HoriHeader
*pHori
;
2345 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2346 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2348 if(height
== 0) height
= 16;
2350 /* Calc. height of EM square:
2352 * For +ve lfHeight we have
2353 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2354 * Re-arranging gives:
2355 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2357 * For -ve lfHeight we have
2359 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2360 * with il = winAscent + winDescent - units_per_em]
2365 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2366 ppem
= ft_face
->units_per_EM
* height
/
2367 (pHori
->Ascender
- pHori
->Descender
);
2369 ppem
= ft_face
->units_per_EM
* height
/
2370 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2378 static struct font_mapping
*map_font_file( const char *name
)
2380 struct font_mapping
*mapping
;
2384 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2385 if (fstat( fd
, &st
) == -1) goto error
;
2387 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2389 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2391 mapping
->refcount
++;
2396 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2399 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2402 if (mapping
->data
== MAP_FAILED
)
2404 HeapFree( GetProcessHeap(), 0, mapping
);
2407 mapping
->refcount
= 1;
2408 mapping
->dev
= st
.st_dev
;
2409 mapping
->ino
= st
.st_ino
;
2410 mapping
->size
= st
.st_size
;
2411 list_add_tail( &mappings_list
, &mapping
->entry
);
2419 static void unmap_font_file( struct font_mapping
*mapping
)
2421 if (!--mapping
->refcount
)
2423 list_remove( &mapping
->entry
);
2424 munmap( mapping
->data
, mapping
->size
);
2425 HeapFree( GetProcessHeap(), 0, mapping
);
2429 static LONG
load_VDMX(GdiFont
*, LONG
);
2431 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2438 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2442 if (!(font
->mapping
= map_font_file( face
->file
)))
2444 WARN("failed to map %s\n", debugstr_a(face
->file
));
2447 data_ptr
= font
->mapping
->data
;
2448 data_size
= font
->mapping
->size
;
2452 data_ptr
= face
->font_data_ptr
;
2453 data_size
= face
->font_data_size
;
2456 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2458 ERR("FT_New_Face rets %d\n", err
);
2462 /* set it here, as load_VDMX needs it */
2463 font
->ft_face
= ft_face
;
2465 if(FT_IS_SCALABLE(ft_face
)) {
2466 /* load the VDMX table if we have one */
2467 font
->ppem
= load_VDMX(font
, height
);
2469 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2471 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2472 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2474 font
->ppem
= height
;
2475 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2476 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2482 static int get_nearest_charset(Face
*face
, int *cp
)
2484 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2485 a single face with the requested charset. The idea is to check if
2486 the selected font supports the current ANSI codepage, if it does
2487 return the corresponding charset, else return the first charset */
2490 int acp
= GetACP(), i
;
2494 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2495 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2496 return csi
.ciCharset
;
2498 for(i
= 0; i
< 32; i
++) {
2500 if(face
->fs
.fsCsb
[0] & fs0
) {
2501 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2503 return csi
.ciCharset
;
2506 FIXME("TCI failing on %x\n", fs0
);
2510 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2511 face
->fs
.fsCsb
[0], face
->file
);
2513 return DEFAULT_CHARSET
;
2516 static GdiFont
*alloc_font(void)
2518 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2520 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2521 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2523 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2524 ret
->total_kern_pairs
= (DWORD
)-1;
2525 ret
->kern_pairs
= NULL
;
2526 list_init(&ret
->hfontlist
);
2527 list_init(&ret
->child_fonts
);
2531 static void free_font(GdiFont
*font
)
2533 struct list
*cursor
, *cursor2
;
2536 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2538 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2539 struct list
*first_hfont
;
2540 HFONTLIST
*hfontlist
;
2541 list_remove(cursor
);
2544 first_hfont
= list_head(&child
->font
->hfontlist
);
2545 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2546 DeleteObject(hfontlist
->hfont
);
2547 HeapFree(GetProcessHeap(), 0, hfontlist
);
2548 free_font(child
->font
);
2550 HeapFree(GetProcessHeap(), 0, child
);
2553 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2554 if (font
->mapping
) unmap_font_file( font
->mapping
);
2555 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2556 HeapFree(GetProcessHeap(), 0, font
->potm
);
2557 HeapFree(GetProcessHeap(), 0, font
->name
);
2558 for (i
= 0; i
< font
->gmsize
; i
++)
2559 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2560 HeapFree(GetProcessHeap(), 0, font
->gm
);
2561 HeapFree(GetProcessHeap(), 0, font
);
2565 /*************************************************************
2568 * load the vdmx entry for the specified height
2571 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2572 ( ( (FT_ULong)_x4 << 24 ) | \
2573 ( (FT_ULong)_x3 << 16 ) | \
2574 ( (FT_ULong)_x2 << 8 ) | \
2577 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2592 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2596 BYTE devXRatio
, devYRatio
;
2597 USHORT numRecs
, numRatios
;
2598 DWORD result
, offset
= -1;
2602 /* For documentation on VDMX records, see
2603 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2606 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2608 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2611 /* FIXME: need the real device aspect ratio */
2615 numRecs
= GET_BE_WORD(hdr
[1]);
2616 numRatios
= GET_BE_WORD(hdr
[2]);
2618 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2619 for(i
= 0; i
< numRatios
; i
++) {
2622 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2623 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2626 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2628 if((ratio
.xRatio
== 0 &&
2629 ratio
.yStartRatio
== 0 &&
2630 ratio
.yEndRatio
== 0) ||
2631 (devXRatio
== ratio
.xRatio
&&
2632 devYRatio
>= ratio
.yStartRatio
&&
2633 devYRatio
<= ratio
.yEndRatio
))
2635 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2636 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2637 offset
= GET_BE_WORD(tmp
);
2643 FIXME("No suitable ratio found\n");
2647 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2649 BYTE startsz
, endsz
;
2652 recs
= GET_BE_WORD(group
.recs
);
2653 startsz
= group
.startsz
;
2654 endsz
= group
.endsz
;
2656 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2658 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2659 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2660 if(result
== GDI_ERROR
) {
2661 FIXME("Failed to retrieve vTable\n");
2666 for(i
= 0; i
< recs
; i
++) {
2667 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2668 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2669 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2671 if(yMax
+ -yMin
== height
) {
2674 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2677 if(yMax
+ -yMin
> height
) {
2680 goto end
; /* failed */
2682 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2683 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2684 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2685 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2691 TRACE("ppem not found for height %d\n", height
);
2695 if(ppem
< startsz
|| ppem
> endsz
)
2698 for(i
= 0; i
< recs
; i
++) {
2700 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2702 if(yPelHeight
> ppem
)
2705 if(yPelHeight
== ppem
) {
2706 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2707 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2708 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2714 HeapFree(GetProcessHeap(), 0, vTable
);
2720 static BOOL
fontcmp(GdiFont
*font
, FONT_DESC
*fd
)
2722 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2723 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2724 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2725 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2726 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2729 static void calc_hash(FONT_DESC
*pfd
)
2731 DWORD hash
= 0, *ptr
, two_chars
;
2735 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2737 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2739 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2741 pwc
= (WCHAR
*)&two_chars
;
2743 *pwc
= toupperW(*pwc
);
2745 *pwc
= toupperW(*pwc
);
2749 hash
^= !pfd
->can_use_bitmap
;
2754 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2759 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2761 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
2762 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2763 fd
.can_use_bitmap
= can_use_bitmap
;
2766 /* try the in-use list */
2767 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2768 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2769 if(!fontcmp(ret
, &fd
)) {
2770 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2771 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2772 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2773 if(hflist
->hfont
== hfont
)
2776 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2777 hflist
->hfont
= hfont
;
2778 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2783 /* then the unused list */
2784 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2785 while(font_elem_ptr
) {
2786 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2787 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2788 if(!fontcmp(ret
, &fd
)) {
2789 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2790 assert(list_empty(&ret
->hfontlist
));
2791 TRACE("Found %p in unused list\n", ret
);
2792 list_remove(&ret
->entry
);
2793 list_add_head(&gdi_font_list
, &ret
->entry
);
2794 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2795 hflist
->hfont
= hfont
;
2796 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2804 /*************************************************************
2805 * create_child_font_list
2807 static BOOL
create_child_font_list(GdiFont
*font
)
2810 SYSTEM_LINKS
*font_link
;
2811 CHILD_FONT
*font_link_entry
, *new_child
;
2813 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2815 if(!strcmpW(font_link
->font_name
, font
->name
))
2817 TRACE("found entry in system list\n");
2818 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2820 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2821 new_child
->face
= font_link_entry
->face
;
2822 new_child
->font
= NULL
;
2823 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2824 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
2834 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2836 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2838 if (pFT_Set_Charmap
)
2841 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2843 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2845 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2847 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2849 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2850 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2852 switch (ft_face
->charmaps
[i
]->platform_id
)
2855 cmap_def
= ft_face
->charmaps
[i
];
2857 case 0: /* Apple Unicode */
2858 cmap0
= ft_face
->charmaps
[i
];
2860 case 1: /* Macintosh */
2861 cmap1
= ft_face
->charmaps
[i
];
2864 cmap2
= ft_face
->charmaps
[i
];
2866 case 3: /* Microsoft */
2867 cmap3
= ft_face
->charmaps
[i
];
2872 if (cmap3
) /* prefer Microsoft cmap table */
2873 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2875 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2877 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2879 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2881 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2883 return ft_err
== FT_Err_Ok
;
2886 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
2889 /*************************************************************
2890 * WineEngCreateFontInstance
2893 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2896 Face
*face
, *best
, *best_bitmap
;
2897 Family
*family
, *last_resort_family
;
2898 struct list
*family_elem_ptr
, *face_elem_ptr
;
2899 INT height
, width
= 0;
2900 unsigned int score
= 0, new_score
;
2901 signed int diff
= 0, newdiff
;
2902 BOOL bd
, it
, can_use_bitmap
;
2907 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2909 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2910 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2911 if(hflist
->hfont
== hfont
)
2915 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
2916 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2918 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2919 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2920 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2923 /* check the cache first */
2924 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2925 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2929 TRACE("not in cache\n");
2930 if(list_empty(&font_list
)) /* No fonts installed */
2932 TRACE("No fonts installed\n");
2935 if(!have_installed_roman_font
)
2937 TRACE("No roman font installed\n");
2943 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
2944 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
2945 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
2946 calc_hash(&ret
->font_desc
);
2947 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2948 hflist
->hfont
= hfont
;
2949 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2952 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2953 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2954 original value lfCharSet. Note this is a special case for
2955 Symbol and doesn't happen at least for "Wingdings*" */
2957 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
2958 lf
.lfCharSet
= SYMBOL_CHARSET
;
2960 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
2961 switch(lf
.lfCharSet
) {
2962 case DEFAULT_CHARSET
:
2963 csi
.fs
.fsCsb
[0] = 0;
2966 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
2967 csi
.fs
.fsCsb
[0] = 0;
2973 if(lf
.lfFaceName
[0] != '\0') {
2975 SYSTEM_LINKS
*font_link
;
2976 CHILD_FONT
*font_link_entry
;
2978 psub
= get_font_subst(&font_subst_list
, lf
.lfFaceName
, lf
.lfCharSet
);
2981 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
2982 debugstr_w(psub
->to
.name
));
2983 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2986 /* We want a match on name and charset or just name if
2987 charset was DEFAULT_CHARSET. If the latter then
2988 we fixup the returned charset later in get_nearest_charset
2989 where we'll either use the charset of the current ansi codepage
2990 or if that's unavailable the first charset that the font supports.
2992 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2993 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2994 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2995 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2996 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2997 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2998 if(face
->scalable
|| can_use_bitmap
)
3005 * Try check the SystemLink list first for a replacement font.
3006 * We may find good replacements there.
3008 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3010 if(!strcmpiW(font_link
->font_name
, lf
.lfFaceName
))
3012 TRACE("found entry in system list\n");
3013 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3015 face
= font_link_entry
->face
;
3016 family
= face
->family
;
3017 if(csi
.fs
.fsCsb
[0] &
3018 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3020 if(face
->scalable
|| can_use_bitmap
)
3028 /* If requested charset was DEFAULT_CHARSET then try using charset
3029 corresponding to the current ansi codepage */
3030 if(!csi
.fs
.fsCsb
[0]) {
3032 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3033 FIXME("TCI failed on codepage %d\n", acp
);
3034 csi
.fs
.fsCsb
[0] = 0;
3036 lf
.lfCharSet
= csi
.ciCharset
;
3039 /* Face families are in the top 4 bits of lfPitchAndFamily,
3040 so mask with 0xF0 before testing */
3042 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3043 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3044 strcpyW(lf
.lfFaceName
, defFixed
);
3045 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3046 strcpyW(lf
.lfFaceName
, defSerif
);
3047 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3048 strcpyW(lf
.lfFaceName
, defSans
);
3050 strcpyW(lf
.lfFaceName
, defSans
);
3051 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3052 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3053 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3054 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3055 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3056 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3057 if(face
->scalable
|| can_use_bitmap
)
3063 last_resort_family
= NULL
;
3064 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3065 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3066 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3067 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3068 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3071 if(can_use_bitmap
&& !last_resort_family
)
3072 last_resort_family
= family
;
3077 if(last_resort_family
) {
3078 family
= last_resort_family
;
3079 csi
.fs
.fsCsb
[0] = 0;
3083 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3084 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3085 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3086 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3087 if(face
->scalable
) {
3088 csi
.fs
.fsCsb
[0] = 0;
3089 WARN("just using first face for now\n");
3092 if(can_use_bitmap
&& !last_resort_family
)
3093 last_resort_family
= family
;
3096 if(!last_resort_family
) {
3097 FIXME("can't find a single appropriate font - bailing\n");
3102 WARN("could only find a bitmap font - this will probably look awful!\n");
3103 family
= last_resort_family
;
3104 csi
.fs
.fsCsb
[0] = 0;
3107 it
= lf
.lfItalic
? 1 : 0;
3108 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3110 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
3111 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
3113 face
= best
= best_bitmap
= NULL
;
3114 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3116 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3118 new_score
= (face
->Italic
^ it
) + (face
->Bold
^ bd
);
3119 if(!best
|| new_score
<= score
)
3121 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3122 face
->Italic
, face
->Bold
, it
, bd
);
3125 if(best
->scalable
&& score
== 0) break;
3129 newdiff
= height
- (signed int)(best
->size
.height
);
3131 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3132 if(!best_bitmap
|| new_score
< score
||
3133 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3135 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3138 if(score
== 0 && diff
== 0) break;
3145 face
= best
->scalable
? best
: best_bitmap
;
3146 ret
->fake_italic
= (it
&& !face
->Italic
);
3147 ret
->fake_bold
= (bd
&& !face
->Bold
);
3149 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
3151 if(csi
.fs
.fsCsb
[0]) {
3152 ret
->charset
= lf
.lfCharSet
;
3153 ret
->codepage
= csi
.ciACP
;
3156 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3158 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3159 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3161 ret
->aveWidth
= abs(lf
.lfWidth
);
3163 if(!face
->scalable
) {
3164 /* Windows uses integer scaling factors for bitmap fonts */
3165 INT scale
, scaled_height
;
3167 if (height
!= 0) height
= diff
;
3169 height
+= face
->size
.height
;
3171 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3172 scaled_height
= scale
* face
->size
.height
;
3173 /* XP allows not more than 10% deviation */
3174 if (scale
> 1 && scaled_height
- height
> scaled_height
/ 10) scale
--;
3175 ret
->scale_y
= scale
;
3177 width
= face
->size
.x_ppem
>> 6;
3178 height
= face
->size
.y_ppem
>> 6;
3182 TRACE("font scale y: %f\n", ret
->scale_y
);
3184 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3192 ret
->ntmFlags
= face
->ntmFlags
;
3194 if (ret
->charset
== SYMBOL_CHARSET
&&
3195 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3198 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3202 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3205 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3206 ret
->name
= strdupW(family
->FamilyName
);
3207 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3208 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3209 create_child_font_list(ret
);
3211 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3213 list_add_head(&gdi_font_list
, &ret
->entry
);
3217 static void dump_gdi_font_list(void)
3220 struct list
*elem_ptr
;
3222 TRACE("---------- gdiFont Cache ----------\n");
3223 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3224 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3225 TRACE("gdiFont=%p %s %d\n",
3226 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3229 TRACE("---------- Unused gdiFont Cache ----------\n");
3230 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3231 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3232 TRACE("gdiFont=%p %s %d\n",
3233 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3237 /*************************************************************
3238 * WineEngDestroyFontInstance
3240 * free the gdiFont associated with this handle
3243 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3248 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3251 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3253 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3254 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3255 if(hflist
->hfont
== handle
)
3257 TRACE("removing child font %p from child list\n", gdiFont
);
3258 list_remove(&gdiFont
->entry
);
3263 TRACE("destroying hfont=%p\n", handle
);
3265 dump_gdi_font_list();
3267 font_elem_ptr
= list_head(&gdi_font_list
);
3268 while(font_elem_ptr
) {
3269 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3270 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3272 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3273 while(hfontlist_elem_ptr
) {
3274 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3275 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3276 if(hflist
->hfont
== handle
) {
3277 list_remove(&hflist
->entry
);
3278 HeapFree(GetProcessHeap(), 0, hflist
);
3282 if(list_empty(&gdiFont
->hfontlist
)) {
3283 TRACE("Moving to Unused list\n");
3284 list_remove(&gdiFont
->entry
);
3285 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3290 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3291 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3292 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3293 while(font_elem_ptr
) {
3294 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3295 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3296 TRACE("freeing %p\n", gdiFont
);
3297 list_remove(&gdiFont
->entry
);
3303 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3304 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3309 if (face
->cached_enum_data
)
3312 memcpy(pelf
, &face
->cached_enum_data
->elf
, sizeof(ENUMLOGFONTEXW
));
3313 memcpy(pntm
, &face
->cached_enum_data
->ntm
, sizeof(NEWTEXTMETRICEXW
));
3314 *ptype
= face
->cached_enum_data
->type
;
3318 font
= alloc_font();
3320 if(face
->scalable
) {
3324 height
= face
->size
.y_ppem
>> 6;
3325 width
= face
->size
.x_ppem
>> 6;
3327 font
->scale_y
= 1.0;
3329 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3335 font
->name
= strdupW(face
->family
->FamilyName
);
3336 font
->ntmFlags
= face
->ntmFlags
;
3338 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3340 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3342 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3344 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3345 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3347 lstrcpynW(pelf
->elfFullName
,
3348 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
3350 lstrcpynW(pelf
->elfStyle
,
3351 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
3356 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
3358 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3360 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3361 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
3362 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
3365 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
3366 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3367 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3368 memcpy(&pntm
->ntmFontSig
, &face
->fs
, sizeof(FONTSIGNATURE
));
3370 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3372 pelf
->elfLogFont
.lfEscapement
= 0;
3373 pelf
->elfLogFont
.lfOrientation
= 0;
3374 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
3375 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3376 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
3377 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
3378 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
3379 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
3380 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
3381 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3382 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3383 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3384 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3387 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
3388 *ptype
|= TRUETYPE_FONTTYPE
;
3389 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
3390 *ptype
|= DEVICE_FONTTYPE
;
3391 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
3392 *ptype
|= RASTER_FONTTYPE
;
3394 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
3395 if (face
->cached_enum_data
)
3397 memcpy(&face
->cached_enum_data
->elf
, pelf
, sizeof(ENUMLOGFONTEXW
));
3398 memcpy(&face
->cached_enum_data
->ntm
, pntm
, sizeof(NEWTEXTMETRICEXW
));
3399 face
->cached_enum_data
->type
= *ptype
;
3405 /*************************************************************
3409 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3413 struct list
*family_elem_ptr
, *face_elem_ptr
;
3415 NEWTEXTMETRICEXW ntm
;
3416 DWORD type
, ret
= 1;
3424 lf
.lfCharSet
= DEFAULT_CHARSET
;
3425 lf
.lfPitchAndFamily
= 0;
3426 lf
.lfFaceName
[0] = 0;
3430 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3432 if(plf
->lfFaceName
[0]) {
3434 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3437 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3438 debugstr_w(psub
->to
.name
));
3439 memcpy(&lf
, plf
, sizeof(lf
));
3440 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3444 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3445 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3446 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3447 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3448 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3449 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3450 for(i
= 0; i
< 32; i
++) {
3451 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3452 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3453 strcpyW(elf
.elfScript
, OEM_DOSW
);
3454 i
= 32; /* break out of loop */
3455 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3458 fs
.fsCsb
[0] = 1L << i
;
3460 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3462 csi
.ciCharset
= DEFAULT_CHARSET
;
3463 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3464 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3465 elf
.elfLogFont
.lfCharSet
=
3466 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3468 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3470 FIXME("Unknown elfscript for bit %d\n", i
);
3473 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3474 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3475 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3476 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3477 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3478 ntm
.ntmTm
.ntmFlags
);
3479 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3486 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3487 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3488 face_elem_ptr
= list_head(&family
->faces
);
3489 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3490 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3491 for(i
= 0; i
< 32; i
++) {
3492 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3493 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3494 strcpyW(elf
.elfScript
, OEM_DOSW
);
3495 i
= 32; /* break out of loop */
3496 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3499 fs
.fsCsb
[0] = 1L << i
;
3501 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3503 csi
.ciCharset
= DEFAULT_CHARSET
;
3504 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3505 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3506 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3509 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3511 FIXME("Unknown elfscript for bit %d\n", i
);
3514 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3515 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3516 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3517 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3518 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3519 ntm
.ntmTm
.ntmFlags
);
3520 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3529 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3531 pt
->x
.value
= vec
->x
>> 6;
3532 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3533 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3534 pt
->y
.value
= vec
->y
>> 6;
3535 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3536 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3540 /***************************************************
3541 * According to the MSDN documentation on WideCharToMultiByte,
3542 * certain codepages cannot set the default_used parameter.
3543 * This returns TRUE if the codepage can set that parameter, false else
3544 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3546 static BOOL
codepage_sets_default_used(UINT codepage
)
3559 static FT_UInt
get_glyph_index(GdiFont
*font
, UINT glyph
)
3561 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
3562 WCHAR wc
= (WCHAR
)glyph
;
3564 BOOL
*default_used_pointer
;
3567 default_used_pointer
= NULL
;
3568 default_used
= FALSE
;
3569 if (codepage_sets_default_used(font
->codepage
))
3570 default_used_pointer
= &default_used
;
3571 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
3574 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
3575 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
3579 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
3580 glyph
= glyph
+ 0xf000;
3581 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
3584 /*************************************************************
3585 * WineEngGetGlyphIndices
3587 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3589 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
3590 LPWORD pgi
, DWORD flags
)
3593 WCHAR default_char
= 0;
3596 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0x001f; /* Indicate non existence */
3598 for(i
= 0; i
< count
; i
++)
3600 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
3605 WineEngGetTextMetrics(font
, &textm
);
3606 default_char
= textm
.tmDefaultChar
;
3608 pgi
[i
] = default_char
;
3614 /*************************************************************
3615 * WineEngGetGlyphOutline
3617 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3618 * except that the first parameter is the HWINEENGFONT of the font in
3619 * question rather than an HDC.
3622 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
3623 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3626 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
3627 FT_Face ft_face
= incoming_font
->ft_face
;
3628 GdiFont
*font
= incoming_font
;
3629 FT_UInt glyph_index
;
3630 DWORD width
, height
, pitch
, needed
= 0;
3631 FT_Bitmap ft_bitmap
;
3633 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
3635 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3636 float widthRatio
= 1.0;
3637 FT_Matrix transMat
= identityMat
;
3638 BOOL needsTransform
= FALSE
;
3641 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
3642 buflen
, buf
, lpmat
);
3644 if(format
& GGO_GLYPH_INDEX
) {
3645 glyph_index
= glyph
;
3646 format
&= ~GGO_GLYPH_INDEX
;
3648 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
3649 ft_face
= font
->ft_face
;
3652 if(glyph_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
3653 font
->gmsize
= (glyph_index
/ GM_BLOCK_SIZE
+ 1);
3654 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
3655 font
->gmsize
* sizeof(GM
*));
3657 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] != NULL
&& FONT_GM(font
,glyph_index
)->init
) {
3658 *lpgm
= FONT_GM(font
,glyph_index
)->gm
;
3659 return 1; /* FIXME */
3663 if (!font
->gm
[glyph_index
/ GM_BLOCK_SIZE
])
3664 font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3666 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) || lpmat
)
3667 load_flags
|= FT_LOAD_NO_BITMAP
;
3669 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
3672 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
3676 /* Scaling factor */
3677 if (font
->aveWidth
&& font
->potm
)
3679 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
3680 widthRatio
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
3683 widthRatio
= font
->scale_y
;
3685 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
3686 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
3688 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
3690 bbx
= (right
- left
) >> 6;
3692 /* Scaling transform */
3693 if(font
->aveWidth
) {
3695 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
3698 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
3700 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
3701 needsTransform
= TRUE
;
3704 /* Slant transform */
3705 if (font
->fake_italic
) {
3708 slantMat
.xx
= (1 << 16);
3709 slantMat
.xy
= ((1 << 16) >> 2);
3711 slantMat
.yy
= (1 << 16);
3712 pFT_Matrix_Multiply(&slantMat
, &transMat
);
3713 needsTransform
= TRUE
;
3716 /* Rotation transform */
3717 if(font
->orientation
) {
3718 FT_Matrix rotationMat
;
3720 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
3721 pFT_Vector_Unit(&vecAngle
, angle
);
3722 rotationMat
.xx
= vecAngle
.x
;
3723 rotationMat
.xy
= -vecAngle
.y
;
3724 rotationMat
.yx
= -rotationMat
.xy
;
3725 rotationMat
.yy
= rotationMat
.xx
;
3727 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
3728 needsTransform
= TRUE
;
3731 /* Extra transformation specified by caller */
3734 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
3735 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
3736 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
3737 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
3738 pFT_Matrix_Multiply(&extraMat
, &transMat
);
3739 needsTransform
= TRUE
;
3742 if(!needsTransform
) {
3743 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
3744 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
3745 ft_face
->glyph
->metrics
.height
) & -64;
3746 lpgm
->gmCellIncX
= adv
;
3747 lpgm
->gmCellIncY
= 0;
3751 for(xc
= 0; xc
< 2; xc
++) {
3752 for(yc
= 0; yc
< 2; yc
++) {
3753 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
3754 xc
* ft_face
->glyph
->metrics
.width
);
3755 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
3756 yc
* ft_face
->glyph
->metrics
.height
;
3757 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
3758 pFT_Vector_Transform(&vec
, &transMat
);
3759 if(xc
== 0 && yc
== 0) {
3760 left
= right
= vec
.x
;
3761 top
= bottom
= vec
.y
;
3763 if(vec
.x
< left
) left
= vec
.x
;
3764 else if(vec
.x
> right
) right
= vec
.x
;
3765 if(vec
.y
< bottom
) bottom
= vec
.y
;
3766 else if(vec
.y
> top
) top
= vec
.y
;
3771 right
= (right
+ 63) & -64;
3772 bottom
= bottom
& -64;
3773 top
= (top
+ 63) & -64;
3775 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
3776 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
3778 pFT_Vector_Transform(&vec
, &transMat
);
3779 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
3780 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
3782 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
3783 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
3784 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
3785 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
3787 if(format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
)
3789 FONT_GM(font
,glyph_index
)->gm
= *lpgm
;
3790 FONT_GM(font
,glyph_index
)->adv
= adv
;
3791 FONT_GM(font
,glyph_index
)->lsb
= lsb
;
3792 FONT_GM(font
,glyph_index
)->bbx
= bbx
;
3793 FONT_GM(font
,glyph_index
)->init
= TRUE
;
3796 if(format
== GGO_METRICS
)
3797 return 1; /* FIXME */
3799 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) {
3800 TRACE("loaded a bitmap\n");
3806 width
= lpgm
->gmBlackBoxX
;
3807 height
= lpgm
->gmBlackBoxY
;
3808 pitch
= ((width
+ 31) >> 5) << 2;
3809 needed
= pitch
* height
;
3811 if(!buf
|| !buflen
) break;
3813 switch(ft_face
->glyph
->format
) {
3814 case ft_glyph_format_bitmap
:
3816 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3817 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
3818 INT h
= ft_face
->glyph
->bitmap
.rows
;
3820 memcpy(dst
, src
, w
);
3821 src
+= ft_face
->glyph
->bitmap
.pitch
;
3827 case ft_glyph_format_outline
:
3828 ft_bitmap
.width
= width
;
3829 ft_bitmap
.rows
= height
;
3830 ft_bitmap
.pitch
= pitch
;
3831 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
3832 ft_bitmap
.buffer
= buf
;
3834 if(needsTransform
) {
3835 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3838 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3840 /* Note: FreeType will only set 'black' bits for us. */
3841 memset(buf
, 0, needed
);
3842 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3846 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3851 case GGO_GRAY2_BITMAP
:
3852 case GGO_GRAY4_BITMAP
:
3853 case GGO_GRAY8_BITMAP
:
3854 case WINE_GGO_GRAY16_BITMAP
:
3856 unsigned int mult
, row
, col
;
3859 width
= lpgm
->gmBlackBoxX
;
3860 height
= lpgm
->gmBlackBoxY
;
3861 pitch
= (width
+ 3) / 4 * 4;
3862 needed
= pitch
* height
;
3864 if(!buf
|| !buflen
) break;
3866 switch(ft_face
->glyph
->format
) {
3867 case ft_glyph_format_bitmap
:
3869 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3870 INT h
= ft_face
->glyph
->bitmap
.rows
;
3873 for(x
= 0; x
< pitch
; x
++)
3874 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
3875 src
+= ft_face
->glyph
->bitmap
.pitch
;
3880 case ft_glyph_format_outline
:
3882 ft_bitmap
.width
= width
;
3883 ft_bitmap
.rows
= height
;
3884 ft_bitmap
.pitch
= pitch
;
3885 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
3886 ft_bitmap
.buffer
= buf
;
3889 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3891 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3893 memset(ft_bitmap
.buffer
, 0, buflen
);
3895 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3897 if(format
== GGO_GRAY2_BITMAP
)
3899 else if(format
== GGO_GRAY4_BITMAP
)
3901 else if(format
== GGO_GRAY8_BITMAP
)
3903 else /* format == WINE_GGO_GRAY16_BITMAP */
3909 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3914 for(row
= 0; row
< height
; row
++) {
3916 for(col
= 0; col
< width
; col
++, ptr
++) {
3917 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
3926 int contour
, point
= 0, first_pt
;
3927 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3928 TTPOLYGONHEADER
*pph
;
3930 DWORD pph_start
, cpfx
, type
;
3932 if(buflen
== 0) buf
= NULL
;
3934 if (needsTransform
&& buf
) {
3935 pFT_Outline_Transform(outline
, &transMat
);
3938 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3940 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3943 pph
->dwType
= TT_POLYGON_TYPE
;
3944 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3946 needed
+= sizeof(*pph
);
3948 while(point
<= outline
->contours
[contour
]) {
3949 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3950 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3951 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3955 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3958 } while(point
<= outline
->contours
[contour
] &&
3959 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3960 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3961 /* At the end of a contour Windows adds the start point, but
3963 if(point
> outline
->contours
[contour
] &&
3964 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3966 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3968 } else if(point
<= outline
->contours
[contour
] &&
3969 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3970 /* add closing pt for bezier */
3972 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3980 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3983 pph
->cb
= needed
- pph_start
;
3989 /* Convert the quadratic Beziers to cubic Beziers.
3990 The parametric eqn for a cubic Bezier is, from PLRM:
3991 r(t) = at^3 + bt^2 + ct + r0
3992 with the control points:
3997 A quadratic Beizer has the form:
3998 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4000 So equating powers of t leads to:
4001 r1 = 2/3 p1 + 1/3 p0
4002 r2 = 2/3 p1 + 1/3 p2
4003 and of course r0 = p0, r3 = p2
4006 int contour
, point
= 0, first_pt
;
4007 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4008 TTPOLYGONHEADER
*pph
;
4010 DWORD pph_start
, cpfx
, type
;
4011 FT_Vector cubic_control
[4];
4012 if(buflen
== 0) buf
= NULL
;
4014 if (needsTransform
&& buf
) {
4015 pFT_Outline_Transform(outline
, &transMat
);
4018 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4020 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4023 pph
->dwType
= TT_POLYGON_TYPE
;
4024 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4026 needed
+= sizeof(*pph
);
4028 while(point
<= outline
->contours
[contour
]) {
4029 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4030 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4031 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
4034 if(type
== TT_PRIM_LINE
) {
4036 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4040 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4043 /* FIXME: Possible optimization in endpoint calculation
4044 if there are two consecutive curves */
4045 cubic_control
[0] = outline
->points
[point
-1];
4046 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4047 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
4048 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
4049 cubic_control
[0].x
>>= 1;
4050 cubic_control
[0].y
>>= 1;
4052 if(point
+1 > outline
->contours
[contour
])
4053 cubic_control
[3] = outline
->points
[first_pt
];
4055 cubic_control
[3] = outline
->points
[point
+1];
4056 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
4057 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
4058 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
4059 cubic_control
[3].x
>>= 1;
4060 cubic_control
[3].y
>>= 1;
4063 /* r1 = 1/3 p0 + 2/3 p1
4064 r2 = 1/3 p2 + 2/3 p1 */
4065 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
4066 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
4067 cubic_control
[2] = cubic_control
[1];
4068 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
4069 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
4070 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
4071 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
4073 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
4074 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
4075 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
4080 } while(point
<= outline
->contours
[contour
] &&
4081 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4082 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4083 /* At the end of a contour Windows adds the start point,
4084 but only for Beziers and we've already done that.
4086 if(point
<= outline
->contours
[contour
] &&
4087 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4088 /* This is the closing pt of a bezier, but we've already
4089 added it, so just inc point and carry on */
4096 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4099 pph
->cb
= needed
- pph_start
;
4105 FIXME("Unsupported format %d\n", format
);
4111 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
4113 FT_Face ft_face
= font
->ft_face
;
4114 #ifdef HAVE_FREETYPE_FTWINFNT_H
4115 FT_WinFNT_HeaderRec winfnt_header
;
4117 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
4118 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
4119 font
->potm
->otmSize
= size
;
4121 #define TM font->potm->otmTextMetrics
4122 #ifdef HAVE_FREETYPE_FTWINFNT_H
4123 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
4125 TM
.tmHeight
= winfnt_header
.pixel_height
;
4126 TM
.tmAscent
= winfnt_header
.ascent
;
4127 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
4128 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
4129 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
4130 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
4131 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4132 TM
.tmWeight
= winfnt_header
.weight
;
4134 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4135 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4136 TM
.tmFirstChar
= winfnt_header
.first_char
;
4137 TM
.tmLastChar
= winfnt_header
.last_char
;
4138 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4139 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4140 TM
.tmItalic
= winfnt_header
.italic
;
4141 TM
.tmUnderlined
= font
->underline
;
4142 TM
.tmStruckOut
= font
->strikeout
;
4143 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4144 TM
.tmCharSet
= winfnt_header
.charset
;
4149 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4150 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4151 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4152 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4153 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4154 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4155 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4156 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4158 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4159 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4161 TM
.tmLastChar
= 255;
4162 TM
.tmDefaultChar
= 32;
4163 TM
.tmBreakChar
= 32;
4164 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4165 TM
.tmUnderlined
= font
->underline
;
4166 TM
.tmStruckOut
= font
->strikeout
;
4167 /* NB inverted meaning of TMPF_FIXED_PITCH */
4168 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4169 TM
.tmCharSet
= font
->charset
;
4177 static void scale_font_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4183 scale_x
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4184 scale_x
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4187 scale_x
= font
->scale_y
;
4189 ptm
->tmHeight
= (float)ptm
->tmHeight
* font
->scale_y
;
4190 ptm
->tmAscent
= (float)ptm
->tmAscent
* font
->scale_y
;
4191 ptm
->tmDescent
= (float)ptm
->tmDescent
* font
->scale_y
;
4192 ptm
->tmInternalLeading
= (float)ptm
->tmInternalLeading
* font
->scale_y
;
4193 ptm
->tmExternalLeading
= (float)ptm
->tmExternalLeading
* font
->scale_y
;
4195 ptm
->tmAveCharWidth
= (float)ptm
->tmAveCharWidth
* scale_x
;
4196 ptm
->tmMaxCharWidth
= (float)ptm
->tmMaxCharWidth
* scale_x
;
4199 /*************************************************************
4200 * WineEngGetTextMetrics
4203 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4206 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4207 if(!get_bitmap_text_metrics(font
))
4210 if(!font
->potm
) return FALSE
;
4211 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
4212 scale_font_metrics(font
, ptm
);
4218 /*************************************************************
4219 * WineEngGetOutlineTextMetrics
4222 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4223 OUTLINETEXTMETRICW
*potm
)
4225 FT_Face ft_face
= font
->ft_face
;
4226 UINT needed
, lenfam
, lensty
, ret
;
4228 TT_HoriHeader
*pHori
;
4229 TT_Postscript
*pPost
;
4230 FT_Fixed x_scale
, y_scale
;
4231 WCHAR
*family_nameW
, *style_nameW
;
4232 static const WCHAR spaceW
[] = {' ', '\0'};
4234 INT ascent
, descent
;
4236 TRACE("font=%p\n", font
);
4238 if(!FT_IS_SCALABLE(ft_face
))
4242 if(cbSize
>= font
->potm
->otmSize
)
4244 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4245 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4247 return font
->potm
->otmSize
;
4251 needed
= sizeof(*potm
);
4253 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
4254 family_nameW
= strdupW(font
->name
);
4256 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
4258 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
4259 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
4260 style_nameW
, lensty
/sizeof(WCHAR
));
4262 /* These names should be read from the TT name table */
4264 /* length of otmpFamilyName */
4267 /* length of otmpFaceName */
4268 if(!strcasecmp(ft_face
->style_name
, "regular")) {
4269 needed
+= lenfam
; /* just the family name */
4271 needed
+= lenfam
+ lensty
; /* family + " " + style */
4274 /* length of otmpStyleName */
4277 /* length of otmpFullName */
4278 needed
+= lenfam
+ lensty
;
4281 x_scale
= ft_face
->size
->metrics
.x_scale
;
4282 y_scale
= ft_face
->size
->metrics
.y_scale
;
4284 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4286 FIXME("Can't find OS/2 table - not TT font?\n");
4291 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4293 FIXME("Can't find HHEA table - not TT font?\n");
4298 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
4300 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",
4301 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
4302 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
4303 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
4304 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
4305 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
4307 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
4308 font
->potm
->otmSize
= needed
;
4310 #define TM font->potm->otmTextMetrics
4312 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
4313 ascent
= pHori
->Ascender
;
4314 descent
= -pHori
->Descender
;
4316 ascent
= pOS2
->usWinAscent
;
4317 descent
= pOS2
->usWinDescent
;
4321 TM
.tmAscent
= font
->yMax
;
4322 TM
.tmDescent
= -font
->yMin
;
4323 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4325 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4326 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4327 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4328 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4331 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4334 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4336 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4337 ((ascent
+ descent
) -
4338 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4340 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4341 if (TM
.tmAveCharWidth
== 0) {
4342 TM
.tmAveCharWidth
= 1;
4344 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4345 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4347 TM
.tmDigitizedAspectX
= 300;
4348 TM
.tmDigitizedAspectY
= 300;
4349 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4350 * symbol range to 0 - f0ff
4352 if (font
->charset
== SYMBOL_CHARSET
)
4355 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4356 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4357 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4358 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4359 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4360 TM
.tmUnderlined
= font
->underline
;
4361 TM
.tmStruckOut
= font
->strikeout
;
4363 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4364 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4365 (pOS2
->version
== 0xFFFFU
||
4366 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4367 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4369 TM
.tmPitchAndFamily
= 0;
4371 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4372 case PAN_FAMILY_SCRIPT
:
4373 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4375 case PAN_FAMILY_DECORATIVE
:
4376 case PAN_FAMILY_PICTORIAL
:
4377 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4379 case PAN_FAMILY_TEXT_DISPLAY
:
4380 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4381 TM
.tmPitchAndFamily
= FF_MODERN
;
4383 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4384 case PAN_SERIF_NORMAL_SANS
:
4385 case PAN_SERIF_OBTUSE_SANS
:
4386 case PAN_SERIF_PERP_SANS
:
4387 TM
.tmPitchAndFamily
|= FF_SWISS
;
4390 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4395 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4398 if(FT_IS_SCALABLE(ft_face
))
4399 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4401 if(FT_IS_SFNT(ft_face
))
4403 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
4404 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
4406 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4409 TM
.tmCharSet
= font
->charset
;
4412 font
->potm
->otmFiller
= 0;
4413 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4414 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4415 font
->potm
->otmfsType
= pOS2
->fsType
;
4416 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4417 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4418 font
->potm
->otmItalicAngle
= 0; /* POST table */
4419 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4420 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4421 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4422 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4423 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4424 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
4425 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4426 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
4427 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
4428 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
4429 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
4430 font
->potm
->otmMacDescent
= 0;
4431 font
->potm
->otmMacLineGap
= 0;
4432 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
4433 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
4434 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
4435 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
4436 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
4437 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
4438 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
4439 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
4440 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
4441 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
4442 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
4444 font
->potm
->otmsUnderscoreSize
= 0;
4445 font
->potm
->otmsUnderscorePosition
= 0;
4447 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
4448 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
4451 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4452 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
4453 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
4454 strcpyW((WCHAR
*)cp
, family_nameW
);
4456 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
4457 strcpyW((WCHAR
*)cp
, style_nameW
);
4459 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
4460 strcpyW((WCHAR
*)cp
, family_nameW
);
4461 if(strcasecmp(ft_face
->style_name
, "regular")) {
4462 strcatW((WCHAR
*)cp
, spaceW
);
4463 strcatW((WCHAR
*)cp
, style_nameW
);
4464 cp
+= lenfam
+ lensty
;
4467 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
4468 strcpyW((WCHAR
*)cp
, family_nameW
);
4469 strcatW((WCHAR
*)cp
, spaceW
);
4470 strcatW((WCHAR
*)cp
, style_nameW
);
4473 if(potm
&& needed
<= cbSize
)
4475 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4476 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4480 HeapFree(GetProcessHeap(), 0, style_nameW
);
4481 HeapFree(GetProcessHeap(), 0, family_nameW
);
4486 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
4488 HFONTLIST
*hfontlist
;
4489 child
->font
= alloc_font();
4490 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
4491 if(!child
->font
->ft_face
)
4493 free_font(child
->font
);
4498 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
4499 child
->font
->orientation
= font
->orientation
;
4500 child
->font
->scale_y
= font
->scale_y
;
4501 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
4502 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
4503 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
4504 child
->font
->base_font
= font
;
4505 list_add_head(&child_font_list
, &child
->font
->entry
);
4506 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
4510 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
4513 CHILD_FONT
*child_font
;
4516 font
= font
->base_font
;
4518 *linked_font
= font
;
4520 if((*glyph
= get_glyph_index(font
, c
)))
4523 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
4525 if(!child_font
->font
)
4526 if(!load_child_font(font
, child_font
))
4529 if(!child_font
->font
->ft_face
)
4531 g
= get_glyph_index(child_font
->font
, c
);
4535 *linked_font
= child_font
->font
;
4542 /*************************************************************
4543 * WineEngGetCharWidth
4546 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4551 FT_UInt glyph_index
;
4552 GdiFont
*linked_font
;
4554 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4556 for(c
= firstChar
; c
<= lastChar
; c
++) {
4557 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4558 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4559 &gm
, 0, NULL
, NULL
);
4560 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
4565 /*************************************************************
4566 * WineEngGetCharABCWidths
4569 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4574 FT_UInt glyph_index
;
4575 GdiFont
*linked_font
;
4577 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4579 if(!FT_IS_SCALABLE(font
->ft_face
))
4582 for(c
= firstChar
; c
<= lastChar
; c
++) {
4583 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4584 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4585 &gm
, 0, NULL
, NULL
);
4586 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
4587 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
4588 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
4589 FONT_GM(linked_font
,glyph_index
)->bbx
;
4594 /*************************************************************
4595 * WineEngGetCharABCWidthsI
4598 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4603 FT_UInt glyph_index
;
4604 GdiFont
*linked_font
;
4606 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
4609 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
4611 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
4612 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4613 &gm
, 0, NULL
, NULL
);
4614 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
4615 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
4616 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
4617 - FONT_GM(linked_font
,c
)->bbx
;
4620 for(c
= 0; c
< count
; c
++) {
4621 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4622 &gm
, 0, NULL
, NULL
);
4623 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
4624 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
4625 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
4626 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
4632 /*************************************************************
4633 * WineEngGetTextExtentExPoint
4636 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4637 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4643 FT_UInt glyph_index
;
4644 GdiFont
*linked_font
;
4646 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
4650 WineEngGetTextMetrics(font
, &tm
);
4651 size
->cy
= tm
.tmHeight
;
4653 for(idx
= 0; idx
< count
; idx
++) {
4654 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
4655 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4656 &gm
, 0, NULL
, NULL
);
4657 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
4659 if (! pnfit
|| ext
<= max_ext
) {
4669 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4673 /*************************************************************
4674 * WineEngGetTextExtentExPointI
4677 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4678 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4685 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
4688 WineEngGetTextMetrics(font
, &tm
);
4689 size
->cy
= tm
.tmHeight
;
4691 for(idx
= 0; idx
< count
; idx
++) {
4692 WineEngGetGlyphOutline(font
, indices
[idx
],
4693 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
4695 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
4697 if (! pnfit
|| ext
<= max_ext
) {
4707 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4711 /*************************************************************
4712 * WineEngGetFontData
4715 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4718 FT_Face ft_face
= font
->ft_face
;
4722 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4723 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
4724 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
4726 if(!FT_IS_SFNT(ft_face
))
4734 if(table
) { /* MS tags differ in endidness from FT ones */
4735 table
= table
>> 24 | table
<< 24 |
4736 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
4739 /* make sure value of len is the value freetype says it needs */
4742 FT_ULong needed
= 0;
4743 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
4744 if( !err
&& needed
< len
) len
= needed
;
4746 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
4749 TRACE("Can't find table %c%c%c%c\n",
4750 /* bytes were reversed */
4751 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4752 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4758 /*************************************************************
4759 * WineEngGetTextFace
4762 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4765 lstrcpynW(str
, font
->name
, count
);
4766 return strlenW(font
->name
);
4768 return strlenW(font
->name
) + 1;
4771 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4773 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
4774 return font
->charset
;
4777 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4779 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
4780 struct list
*first_hfont
;
4783 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
4784 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
4785 if(font
== linked_font
)
4786 *new_hfont
= dc
->hFont
;
4789 first_hfont
= list_head(&linked_font
->hfontlist
);
4790 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
4796 /* Retrieve a list of supported Unicode ranges for a given font.
4797 * Can be called with NULL gs to calculate the buffer size. Returns
4798 * the number of ranges found.
4800 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
4802 DWORD num_ranges
= 0;
4804 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4807 FT_ULong char_code
, char_code_prev
;
4810 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
4812 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4813 face
->num_glyphs
, glyph_code
, char_code
);
4815 if (!glyph_code
) return 0;
4819 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4820 gs
->ranges
[0].cGlyphs
= 0;
4821 gs
->cGlyphsSupported
= 0;
4827 if (char_code
< char_code_prev
)
4829 ERR("expected increasing char code from FT_Get_Next_Char\n");
4832 if (char_code
- char_code_prev
> 1)
4837 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4838 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4839 gs
->cGlyphsSupported
++;
4844 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4845 gs
->cGlyphsSupported
++;
4847 char_code_prev
= char_code
;
4848 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
4852 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
4857 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
4860 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
4862 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
4865 glyphset
->cbThis
= size
;
4866 glyphset
->cRanges
= num_ranges
;
4871 /*************************************************************
4874 BOOL
WineEngFontIsLinked(GdiFont
*font
)
4876 return !list_empty(&font
->child_fonts
);
4879 static BOOL
is_hinting_enabled(void)
4881 /* Use the >= 2.2.0 function if available */
4882 if(pFT_Get_TrueType_Engine_Type
)
4884 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
4885 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
4887 #ifdef FT_DRIVER_HAS_HINTER
4892 /* otherwise if we've been compiled with < 2.2.0 headers
4893 use the internal macro */
4894 mod
= pFT_Get_Module(library
, "truetype");
4895 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
4903 /*************************************************************************
4904 * GetRasterizerCaps (GDI32.@)
4906 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
4908 static int hinting
= -1;
4912 hinting
= is_hinting_enabled();
4913 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
4916 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
4917 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
4918 lprs
->nLanguageID
= 0;
4922 /*************************************************************************
4923 * Kerning support for TrueType fonts
4925 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4927 struct TT_kern_table
4933 struct TT_kern_subtable
4942 USHORT horizontal
: 1;
4944 USHORT cross_stream
: 1;
4945 USHORT override
: 1;
4946 USHORT reserved1
: 4;
4952 struct TT_format0_kern_subtable
4956 USHORT entrySelector
;
4967 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
4968 const struct TT_format0_kern_subtable
*tt_f0_ks
,
4969 const USHORT
*glyph_to_char
,
4970 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
4973 const struct TT_kern_pair
*tt_kern_pair
;
4975 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
4977 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
4979 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4980 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
4981 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
4983 if (!kern_pair
|| !cPairs
)
4986 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
4988 nPairs
= min(nPairs
, cPairs
);
4990 for (i
= 0; i
< nPairs
; i
++)
4992 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
4993 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
4994 /* this algorithm appears to better match what Windows does */
4995 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
4996 if (kern_pair
->iKernAmount
< 0)
4998 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
4999 kern_pair
->iKernAmount
-= font
->ppem
;
5001 else if (kern_pair
->iKernAmount
> 0)
5003 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
5004 kern_pair
->iKernAmount
+= font
->ppem
;
5006 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
5008 TRACE("left %u right %u value %d\n",
5009 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
5013 TRACE("copied %u entries\n", nPairs
);
5017 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5021 const struct TT_kern_table
*tt_kern_table
;
5022 const struct TT_kern_subtable
*tt_kern_subtable
;
5024 USHORT
*glyph_to_char
;
5026 if (font
->total_kern_pairs
!= (DWORD
)-1)
5028 if (cPairs
&& kern_pair
)
5030 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5031 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5034 return font
->total_kern_pairs
;
5037 font
->total_kern_pairs
= 0;
5039 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
5041 if (length
== GDI_ERROR
)
5043 TRACE("no kerning data in the font\n");
5047 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
5050 WARN("Out of memory\n");
5054 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
5056 /* build a glyph index to char code map */
5057 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
5060 WARN("Out of memory allocating a glyph index to char code map\n");
5061 HeapFree(GetProcessHeap(), 0, buf
);
5065 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5071 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
5073 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5074 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
5078 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5080 /* FIXME: This doesn't match what Windows does: it does some fancy
5081 * things with duplicate glyph index to char code mappings, while
5082 * we just avoid overriding existing entries.
5084 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
5085 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
5087 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
5094 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
5095 for (n
= 0; n
<= 65535; n
++)
5096 glyph_to_char
[n
] = (USHORT
)n
;
5099 tt_kern_table
= buf
;
5100 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
5101 TRACE("version %u, nTables %u\n",
5102 GET_BE_WORD(tt_kern_table
->version
), nTables
);
5104 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
5106 for (i
= 0; i
< nTables
; i
++)
5108 struct TT_kern_subtable tt_kern_subtable_copy
;
5110 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
5111 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
5112 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
5114 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5115 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
5116 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
5118 /* According to the TrueType specification this is the only format
5119 * that will be properly interpreted by Windows and OS/2
5121 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
5123 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
5125 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5126 glyph_to_char
, NULL
, 0);
5127 font
->total_kern_pairs
+= new_chunk
;
5129 if (!font
->kern_pairs
)
5130 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
5131 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5133 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
5134 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5136 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5137 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
5140 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
5142 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
5145 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
5146 HeapFree(GetProcessHeap(), 0, buf
);
5148 if (cPairs
&& kern_pair
)
5150 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5151 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5154 return font
->total_kern_pairs
;
5157 #else /* HAVE_FREETYPE */
5159 /*************************************************************************/
5161 BOOL
WineEngInit(void)
5165 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
5169 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
5174 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5179 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
5180 LPWORD pgi
, DWORD flags
)
5185 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
5186 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5189 ERR("called but we don't have FreeType\n");
5193 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5195 ERR("called but we don't have FreeType\n");
5199 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5200 OUTLINETEXTMETRICW
*potm
)
5202 ERR("called but we don't have FreeType\n");
5206 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5209 ERR("called but we don't have FreeType\n");
5213 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5216 ERR("called but we don't have FreeType\n");
5220 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5223 ERR("called but we don't have FreeType\n");
5227 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5228 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5230 ERR("called but we don't have FreeType\n");
5234 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5235 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5237 ERR("called but we don't have FreeType\n");
5241 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5244 ERR("called but we don't have FreeType\n");
5248 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5250 ERR("called but we don't have FreeType\n");
5254 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5260 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5266 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
5272 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5275 return DEFAULT_CHARSET
;
5278 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5283 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5285 FIXME("(%p, %p): stub\n", font
, glyphset
);
5289 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5294 /*************************************************************************
5295 * GetRasterizerCaps (GDI32.@)
5297 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5299 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5301 lprs
->nLanguageID
= 0;
5305 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5307 ERR("called but we don't have FreeType\n");
5311 #endif /* HAVE_FREETYPE */