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
{
314 struct list hfontlist
;
315 OUTLINETEXTMETRICW
*potm
;
316 DWORD total_kern_pairs
;
317 KERNINGPAIR
*kern_pairs
;
318 struct list child_fonts
;
320 /* the following members can be accessed without locking, they are never modified after creation */
322 struct font_mapping
*mapping
;
343 const WCHAR
*font_name
;
347 #define GM_BLOCK_SIZE 128
348 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
350 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
351 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
352 #define UNUSED_CACHE_SIZE 10
353 static struct list child_font_list
= LIST_INIT(child_font_list
);
354 static struct list system_links
= LIST_INIT(system_links
);
356 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
358 static struct list font_list
= LIST_INIT(font_list
);
360 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
361 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
362 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
364 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
366 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
367 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
368 'W','i','n','d','o','w','s','\\',
369 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
370 'F','o','n','t','s','\0'};
372 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
373 'W','i','n','d','o','w','s',' ','N','T','\\',
374 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
375 'F','o','n','t','s','\0'};
377 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
378 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
379 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
380 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
382 static const WCHAR
* const SystemFontValues
[4] = {
389 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
390 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
392 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
393 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
394 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
395 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
396 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
397 'E','u','r','o','p','e','a','n','\0'};
398 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
399 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
400 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
401 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
402 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
403 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
404 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
405 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
406 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
407 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
408 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
409 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
411 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
421 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
429 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
438 typedef struct tagFontSubst
{
454 static struct list mappings_list
= LIST_INIT( mappings_list
);
456 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
458 static CRITICAL_SECTION freetype_cs
;
459 static CRITICAL_SECTION_DEBUG critsect_debug
=
462 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
463 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
465 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
467 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
469 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
470 static BOOL use_default_fallback
= FALSE
;
472 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
474 /****************************************
475 * Notes on .fon files
477 * The fonts System, FixedSys and Terminal are special. There are typically multiple
478 * versions installed for different resolutions and codepages. Windows stores which one to use
479 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
481 * FIXEDFON.FON FixedSys
483 * OEMFONT.FON Terminal
484 * LogPixels Current dpi set by the display control panel applet
485 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
486 * also has a LogPixels value that appears to mirror this)
488 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
489 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
490 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
491 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
492 * so that makes sense.
494 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
495 * to be mapped into the registry on Windows 2000 at least).
498 * ega80woa.fon=ega80850.fon
499 * ega40woa.fon=ega40850.fon
500 * cga80woa.fon=cga80850.fon
501 * cga40woa.fon=cga40850.fon
504 #ifdef HAVE_CARBON_CARBON_H
505 static char *find_cache_dir(void)
509 static char cached_path
[MAX_PATH
];
510 static const char *wine
= "/Wine", *fonts
= "/Fonts";
512 if(*cached_path
) return cached_path
;
514 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
517 WARN("can't create cached data folder\n");
520 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
523 WARN("can't create cached data path\n");
527 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
529 ERR("Could not create full path\n");
533 strcat(cached_path
, wine
);
535 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
537 WARN("Couldn't mkdir %s\n", cached_path
);
541 strcat(cached_path
, fonts
);
542 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
544 WARN("Couldn't mkdir %s\n", cached_path
);
551 /******************************************************************
554 * Extracts individual TrueType font files from a Mac suitcase font
555 * and saves them into the user's caches directory (see
557 * Returns a NULL terminated array of filenames.
559 * We do this because they are apps that try to read ttf files
560 * themselves and they don't like Mac suitcase files.
562 static char **expand_mac_font(const char *path
)
569 const char *filename
;
573 unsigned int size
, max_size
;
576 TRACE("path %s\n", path
);
578 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
581 WARN("failed to get ref\n");
585 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
588 TRACE("no data fork, so trying resource fork\n");
589 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
592 TRACE("unable to open resource fork\n");
599 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
602 CloseResFile(res_ref
);
606 out_dir
= find_cache_dir();
608 filename
= strrchr(path
, '/');
609 if(!filename
) filename
= path
;
612 /* output filename has the form out_dir/filename_%04x.ttf */
613 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
620 unsigned short *num_faces_ptr
, num_faces
, face
;
623 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
625 fond
= Get1IndResource(fond_res
, idx
);
627 TRACE("got fond resource %d\n", idx
);
630 fam_rec
= *(FamRec
**)fond
;
631 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
632 num_faces
= GET_BE_WORD(*num_faces_ptr
);
634 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
635 TRACE("num faces %04x\n", num_faces
);
636 for(face
= 0; face
< num_faces
; face
++, assoc
++)
639 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
640 unsigned short size
, font_id
;
643 size
= GET_BE_WORD(assoc
->fontSize
);
644 font_id
= GET_BE_WORD(assoc
->fontID
);
647 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
651 TRACE("trying to load sfnt id %04x\n", font_id
);
652 sfnt
= GetResource(sfnt_res
, font_id
);
655 TRACE("can't get sfnt resource %04x\n", font_id
);
659 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
664 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
666 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
667 if(fd
!= -1 || errno
== EEXIST
)
671 unsigned char *sfnt_data
;
674 sfnt_data
= *(unsigned char**)sfnt
;
675 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
679 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
682 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
684 ret
.array
[ret
.size
++] = output
;
688 WARN("unable to create %s\n", output
);
689 HeapFree(GetProcessHeap(), 0, output
);
692 ReleaseResource(sfnt
);
695 ReleaseResource(fond
);
698 CloseResFile(res_ref
);
703 #endif /* HAVE_CARBON_CARBON_H */
705 static inline BOOL
is_win9x(void)
707 return GetVersion() & 0x80000000;
710 This function builds an FT_Fixed from a float. It puts the integer part
711 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
712 It fails if the integer part of the float number is greater than SHORT_MAX.
714 static inline FT_Fixed
FT_FixedFromFloat(float f
)
717 unsigned short fract
= (f
- value
) * 0xFFFF;
718 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
722 This function builds an FT_Fixed from a FIXED. It simply put f.value
723 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
725 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
727 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
731 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
736 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
737 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
739 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
740 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
742 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
744 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
746 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
750 file
= strrchr(face
->file
, '/');
755 if(!strcasecmp(file
, file_nameA
))
757 HeapFree(GetProcessHeap(), 0, file_nameA
);
762 HeapFree(GetProcessHeap(), 0, file_nameA
);
766 static Family
*find_family_from_name(const WCHAR
*name
)
770 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
772 if(!strcmpiW(family
->FamilyName
, name
))
779 static void DumpSubstList(void)
783 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
785 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
786 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
787 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
789 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
790 debugstr_w(psub
->to
.name
));
795 static LPWSTR
strdupW(LPCWSTR p
)
798 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
799 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
804 static LPSTR
strdupA(LPCSTR p
)
807 DWORD len
= (strlen(p
) + 1);
808 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
813 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
818 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
820 if(!strcmpiW(element
->from
.name
, from_name
) &&
821 (element
->from
.charset
== from_charset
||
822 element
->from
.charset
== -1))
829 #define ADD_FONT_SUBST_FORCE 1
831 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
833 FontSubst
*from_exist
, *to_exist
;
835 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
837 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
839 list_remove(&from_exist
->entry
);
840 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
841 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
842 HeapFree(GetProcessHeap(), 0, from_exist
);
848 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
852 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
853 subst
->to
.name
= strdupW(to_exist
->to
.name
);
856 list_add_tail(subst_list
, &subst
->entry
);
861 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
862 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
863 HeapFree(GetProcessHeap(), 0, subst
);
867 static void split_subst_info(NameCs
*nc
, LPSTR str
)
869 CHAR
*p
= strrchr(str
, ',');
874 nc
->charset
= strtol(p
+1, NULL
, 10);
877 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
878 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
879 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
882 static void LoadSubstList(void)
886 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
890 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
891 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
892 &hkey
) == ERROR_SUCCESS
) {
894 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
895 &valuelen
, &datalen
, NULL
, NULL
);
897 valuelen
++; /* returned value doesn't include room for '\0' */
898 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
899 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
903 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
904 &dlen
) == ERROR_SUCCESS
) {
905 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
907 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
908 split_subst_info(&psub
->from
, value
);
909 split_subst_info(&psub
->to
, data
);
911 /* Win 2000 doesn't allow mapping between different charsets
912 or mapping of DEFAULT_CHARSET */
913 if((psub
->to
.charset
!= psub
->from
.charset
) ||
914 psub
->to
.charset
== DEFAULT_CHARSET
) {
915 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
916 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
917 HeapFree(GetProcessHeap(), 0, psub
);
919 add_font_subst(&font_subst_list
, psub
, 0);
921 /* reset dlen and vlen */
925 HeapFree(GetProcessHeap(), 0, data
);
926 HeapFree(GetProcessHeap(), 0, value
);
931 static WCHAR
*get_familyname(FT_Face ft_face
)
933 WCHAR
*family
= NULL
;
935 FT_UInt num_names
, name_index
, i
;
937 if(FT_IS_SFNT(ft_face
))
939 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
941 for(name_index
= 0; name_index
< num_names
; name_index
++)
943 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
945 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
946 (name
.language_id
== GetUserDefaultLCID()) &&
947 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
948 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
950 /* String is not nul terminated and string_len is a byte length. */
951 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
952 for(i
= 0; i
< name
.string_len
/ 2; i
++)
954 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
955 family
[i
] = GET_BE_WORD(*tmp
);
959 TRACE("Got localised name %s\n", debugstr_w(family
));
970 /*****************************************************************
973 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
974 * of FreeType that don't export this function.
977 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
982 /* If the FT_Load_Sfnt_Table function is there we'll use it */
983 if(pFT_Load_Sfnt_Table
)
985 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
987 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
988 else /* Do it the hard way */
990 TT_Face tt_face
= (TT_Face
) ft_face
;
991 SFNT_Interface
*sfnt
;
992 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
995 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
999 /* A field was added in the middle of the structure in 2.1.x */
1000 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1002 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1010 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1011 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1012 "Please upgrade your freetype library.\n");
1015 err
= FT_Err_Unimplemented_Feature
;
1022 #define ADDFONT_EXTERNAL_FONT 0x01
1023 #define ADDFONT_FORCE_BITMAP 0x02
1024 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1028 TT_Header
*pHeader
= NULL
;
1029 WCHAR
*english_family
, *localised_family
, *StyleW
;
1033 struct list
*family_elem_ptr
, *face_elem_ptr
;
1035 FT_Long face_index
= 0, num_faces
;
1036 #ifdef HAVE_FREETYPE_FTWINFNT_H
1037 FT_WinFNT_HeaderRec winfnt_header
;
1039 int i
, bitmap_num
, internal_leading
;
1042 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1043 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1045 #ifdef HAVE_CARBON_CARBON_H
1046 if(file
&& !fake_family
)
1048 char **mac_list
= expand_mac_font(file
);
1051 BOOL had_one
= FALSE
;
1053 for(cursor
= mac_list
; *cursor
; cursor
++)
1056 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1057 HeapFree(GetProcessHeap(), 0, *cursor
);
1059 HeapFree(GetProcessHeap(), 0, mac_list
);
1064 #endif /* HAVE_CARBON_CARBON_H */
1067 char *family_name
= fake_family
;
1071 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1072 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1075 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1076 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1080 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1084 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*/
1085 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1086 pFT_Done_Face(ft_face
);
1090 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1091 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1092 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1093 pFT_Done_Face(ft_face
);
1097 if(FT_IS_SFNT(ft_face
))
1099 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1100 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1101 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1103 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1104 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1105 pFT_Done_Face(ft_face
);
1109 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1110 we don't want to load these. */
1111 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1115 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1117 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1118 pFT_Done_Face(ft_face
);
1124 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1125 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1126 pFT_Done_Face(ft_face
);
1132 localised_family
= get_familyname(ft_face
);
1133 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1135 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1136 HeapFree(GetProcessHeap(), 0, localised_family
);
1137 num_faces
= ft_face
->num_faces
;
1138 pFT_Done_Face(ft_face
);
1141 HeapFree(GetProcessHeap(), 0, localised_family
);
1145 family_name
= ft_face
->family_name
;
1149 My_FT_Bitmap_Size
*size
= NULL
;
1152 if(!FT_IS_SCALABLE(ft_face
))
1153 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1155 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1156 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1157 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1159 localised_family
= NULL
;
1161 localised_family
= get_familyname(ft_face
);
1162 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1163 HeapFree(GetProcessHeap(), 0, localised_family
);
1164 localised_family
= NULL
;
1169 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1170 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1171 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1176 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1177 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1178 list_init(&family
->faces
);
1179 list_add_tail(&font_list
, &family
->entry
);
1181 if(localised_family
) {
1182 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1183 subst
->from
.name
= strdupW(english_family
);
1184 subst
->from
.charset
= -1;
1185 subst
->to
.name
= strdupW(localised_family
);
1186 subst
->to
.charset
= -1;
1187 add_font_subst(&font_subst_list
, subst
, 0);
1190 HeapFree(GetProcessHeap(), 0, localised_family
);
1191 HeapFree(GetProcessHeap(), 0, english_family
);
1193 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1194 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1195 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1197 internal_leading
= 0;
1198 memset(&fs
, 0, sizeof(fs
));
1200 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1202 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1203 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1204 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1205 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1206 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1207 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1208 if(pOS2
->version
== 0) {
1211 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1212 fs
.fsCsb
[0] |= FS_LATIN1
;
1214 fs
.fsCsb
[0] |= FS_SYMBOL
;
1217 #ifdef HAVE_FREETYPE_FTWINFNT_H
1218 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1220 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1221 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1222 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1223 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
1224 internal_leading
= winfnt_header
.internal_leading
;
1228 face_elem_ptr
= list_head(&family
->faces
);
1229 while(face_elem_ptr
) {
1230 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1231 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1232 if(!strcmpW(face
->StyleName
, StyleW
) &&
1233 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1234 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1235 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1236 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1239 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1240 HeapFree(GetProcessHeap(), 0, StyleW
);
1241 pFT_Done_Face(ft_face
);
1244 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1245 TRACE("Original font is newer so skipping this one\n");
1246 HeapFree(GetProcessHeap(), 0, StyleW
);
1247 pFT_Done_Face(ft_face
);
1250 TRACE("Replacing original with this one\n");
1251 list_remove(&face
->entry
);
1252 HeapFree(GetProcessHeap(), 0, face
->file
);
1253 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1254 HeapFree(GetProcessHeap(), 0, face
);
1259 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1260 face
->cached_enum_data
= NULL
;
1261 list_add_tail(&family
->faces
, &face
->entry
);
1262 face
->StyleName
= StyleW
;
1265 face
->file
= strdupA(file
);
1266 face
->font_data_ptr
= NULL
;
1267 face
->font_data_size
= 0;
1272 face
->font_data_ptr
= font_data_ptr
;
1273 face
->font_data_size
= font_data_size
;
1275 face
->face_index
= face_index
;
1276 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
1277 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
1278 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1279 face
->family
= family
;
1280 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1281 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
1282 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1284 if(FT_IS_SCALABLE(ft_face
)) {
1285 memset(&face
->size
, 0, sizeof(face
->size
));
1286 face
->scalable
= TRUE
;
1288 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1289 size
->height
, size
->width
, size
->size
>> 6,
1290 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1291 face
->size
.height
= size
->height
;
1292 face
->size
.width
= size
->width
;
1293 face
->size
.size
= size
->size
;
1294 face
->size
.x_ppem
= size
->x_ppem
;
1295 face
->size
.y_ppem
= size
->y_ppem
;
1296 face
->size
.internal_leading
= internal_leading
;
1297 face
->scalable
= FALSE
;
1300 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1302 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1304 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1305 face
->ntmFlags
= NTM_PS_OPENTYPE
;
1310 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1311 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1312 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1313 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1316 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1317 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1318 switch(ft_face
->charmaps
[i
]->encoding
) {
1319 case FT_ENCODING_UNICODE
:
1320 case FT_ENCODING_APPLE_ROMAN
:
1321 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1323 case FT_ENCODING_MS_SYMBOL
:
1324 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1332 if (!(face
->fs
.fsCsb
[0] & FS_SYMBOL
))
1333 have_installed_roman_font
= TRUE
;
1334 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1336 num_faces
= ft_face
->num_faces
;
1337 pFT_Done_Face(ft_face
);
1338 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1339 debugstr_w(StyleW
));
1340 } while(num_faces
> ++face_index
);
1344 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1346 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1349 static void DumpFontList(void)
1353 struct list
*family_elem_ptr
, *face_elem_ptr
;
1355 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1356 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1357 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1358 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1359 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1360 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1362 TRACE(" %d", face
->size
.height
);
1369 /***********************************************************
1370 * The replacement list is a way to map an entire font
1371 * family onto another family. For example adding
1373 * [HKCU\Software\Wine\Fonts\Replacements]
1374 * "Wingdings"="Winedings"
1376 * would enumerate the Winedings font both as Winedings and
1377 * Wingdings. However if a real Wingdings font is present the
1378 * replacement does not take place.
1381 static void LoadReplaceList(void)
1384 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1389 struct list
*family_elem_ptr
, *face_elem_ptr
;
1392 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1393 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1395 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1396 &valuelen
, &datalen
, NULL
, NULL
);
1398 valuelen
++; /* returned value doesn't include room for '\0' */
1399 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1400 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1404 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1405 &dlen
) == ERROR_SUCCESS
) {
1406 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1407 /* "NewName"="Oldname" */
1408 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1410 /* Find the old family and hence all of the font files
1412 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1413 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1414 if(!strcmpiW(family
->FamilyName
, data
)) {
1415 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1416 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1417 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1418 debugstr_w(face
->StyleName
), familyA
);
1419 /* Now add a new entry with the new family name */
1420 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1425 /* reset dlen and vlen */
1429 HeapFree(GetProcessHeap(), 0, data
);
1430 HeapFree(GetProcessHeap(), 0, value
);
1435 /*************************************************************
1438 static BOOL
init_system_links(void)
1440 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1441 'W','i','n','d','o','w','s',' ','N','T','\\',
1442 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1443 'S','y','s','t','e','m','L','i','n','k',0};
1446 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1447 WCHAR
*value
, *data
;
1448 WCHAR
*entry
, *next
;
1449 SYSTEM_LINKS
*font_link
, *system_font_link
;
1450 CHILD_FONT
*child_font
;
1451 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1452 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1453 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1459 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1461 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1462 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1463 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1464 val_len
= max_val
+ 1;
1465 data_len
= max_data
;
1467 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1469 TRACE("%s:\n", debugstr_w(value
));
1471 memset(&fs
, 0, sizeof(fs
));
1472 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1473 psub
= get_font_subst(&font_subst_list
, value
, -1);
1474 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1475 list_init(&font_link
->links
);
1476 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1479 CHILD_FONT
*child_font
;
1481 TRACE("\t%s\n", debugstr_w(entry
));
1483 next
= entry
+ strlenW(entry
) + 1;
1485 face_name
= strchrW(entry
, ',');
1489 while(isspaceW(*face_name
))
1492 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1494 face_name
= psub
->to
.name
;
1496 face
= find_face_from_filename(entry
, face_name
);
1499 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1503 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1504 child_font
->face
= face
;
1505 child_font
->font
= NULL
;
1506 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1507 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1508 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1509 list_add_tail(&font_link
->links
, &child_font
->entry
);
1511 family
= find_family_from_name(font_link
->font_name
);
1514 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1516 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
1519 list_add_tail(&system_links
, &font_link
->entry
);
1520 val_len
= max_val
+ 1;
1521 data_len
= max_data
;
1524 HeapFree(GetProcessHeap(), 0, value
);
1525 HeapFree(GetProcessHeap(), 0, data
);
1529 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1532 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1533 system_font_link
->font_name
= strdupW(System
);
1534 list_init(&system_font_link
->links
);
1536 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1539 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1540 child_font
->face
= face
;
1541 child_font
->font
= NULL
;
1542 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1543 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1545 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1547 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1549 CHILD_FONT
*font_link_entry
;
1550 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1552 CHILD_FONT
*new_child
;
1553 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1554 new_child
->face
= font_link_entry
->face
;
1555 new_child
->font
= NULL
;
1556 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1561 list_add_tail(&system_links
, &system_font_link
->entry
);
1565 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1568 struct dirent
*dent
;
1569 char path
[MAX_PATH
];
1571 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1573 dir
= opendir(dirname
);
1575 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1578 while((dent
= readdir(dir
)) != NULL
) {
1579 struct stat statbuf
;
1581 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1584 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1586 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1588 if(stat(path
, &statbuf
) == -1)
1590 WARN("Can't stat %s\n", debugstr_a(path
));
1593 if(S_ISDIR(statbuf
.st_mode
))
1594 ReadFontDir(path
, external_fonts
);
1596 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1602 static void load_fontconfig_fonts(void)
1604 #ifdef SONAME_LIBFONTCONFIG
1605 void *fc_handle
= NULL
;
1614 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1616 TRACE("Wine cannot find the fontconfig library (%s).\n",
1617 SONAME_LIBFONTCONFIG
);
1620 #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;}
1621 LOAD_FUNCPTR(FcConfigGetCurrent
);
1622 LOAD_FUNCPTR(FcFontList
);
1623 LOAD_FUNCPTR(FcFontSetDestroy
);
1624 LOAD_FUNCPTR(FcInit
);
1625 LOAD_FUNCPTR(FcObjectSetAdd
);
1626 LOAD_FUNCPTR(FcObjectSetCreate
);
1627 LOAD_FUNCPTR(FcObjectSetDestroy
);
1628 LOAD_FUNCPTR(FcPatternCreate
);
1629 LOAD_FUNCPTR(FcPatternDestroy
);
1630 LOAD_FUNCPTR(FcPatternGetBool
);
1631 LOAD_FUNCPTR(FcPatternGetString
);
1634 if(!pFcInit()) return;
1636 config
= pFcConfigGetCurrent();
1637 pat
= pFcPatternCreate();
1638 os
= pFcObjectSetCreate();
1639 pFcObjectSetAdd(os
, FC_FILE
);
1640 pFcObjectSetAdd(os
, FC_SCALABLE
);
1641 fontset
= pFcFontList(config
, pat
, os
);
1642 if(!fontset
) return;
1643 for(i
= 0; i
< fontset
->nfont
; i
++) {
1646 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1648 TRACE("fontconfig: %s\n", file
);
1650 /* We're just interested in OT/TT fonts for now, so this hack just
1651 picks up the scalable fonts without extensions .pf[ab] to save time
1652 loading every other font */
1654 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1656 TRACE("not scalable\n");
1660 len
= strlen( file
);
1661 if(len
< 4) continue;
1662 ext
= &file
[ len
- 3 ];
1663 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1664 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1666 pFcFontSetDestroy(fontset
);
1667 pFcObjectSetDestroy(os
);
1668 pFcPatternDestroy(pat
);
1674 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1677 const char *data_dir
= wine_get_data_dir();
1679 if (!data_dir
) data_dir
= wine_get_build_dir();
1686 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1688 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1690 strcpy(unix_name
, data_dir
);
1691 strcat(unix_name
, "/fonts/");
1693 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1695 EnterCriticalSection( &freetype_cs
);
1696 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1697 LeaveCriticalSection( &freetype_cs
);
1698 HeapFree(GetProcessHeap(), 0, unix_name
);
1703 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1705 static const WCHAR slashW
[] = {'\\','\0'};
1707 WCHAR windowsdir
[MAX_PATH
];
1710 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1711 strcatW(windowsdir
, fontsW
);
1712 strcatW(windowsdir
, slashW
);
1713 strcatW(windowsdir
, file
);
1714 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1715 EnterCriticalSection( &freetype_cs
);
1716 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1717 LeaveCriticalSection( &freetype_cs
);
1718 HeapFree(GetProcessHeap(), 0, unixname
);
1723 static void load_system_fonts(void)
1726 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1727 const WCHAR
* const *value
;
1729 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1732 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1733 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1734 strcatW(windowsdir
, fontsW
);
1735 for(value
= SystemFontValues
; *value
; value
++) {
1736 dlen
= sizeof(data
);
1737 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1741 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1742 if((unixname
= wine_get_unix_file_name(pathW
))) {
1743 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1744 HeapFree(GetProcessHeap(), 0, unixname
);
1747 load_font_from_data_dir(data
);
1754 /*************************************************************
1756 * This adds registry entries for any externally loaded fonts
1757 * (fonts from fontconfig or FontDirs). It also deletes entries
1758 * of no longer existing fonts.
1761 static void update_reg_entries(void)
1763 HKEY winkey
= 0, externalkey
= 0;
1766 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
1769 struct list
*family_elem_ptr
, *face_elem_ptr
;
1771 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1772 static const WCHAR spaceW
[] = {' ', '\0'};
1775 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1776 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
1777 ERR("Can't create Windows font reg key\n");
1780 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1781 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
1782 ERR("Can't create external font reg key\n");
1786 /* Delete all external fonts added last time */
1788 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1789 &valuelen
, &datalen
, NULL
, NULL
);
1790 valuelen
++; /* returned value doesn't include room for '\0' */
1791 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1792 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1794 dlen
= datalen
* sizeof(WCHAR
);
1797 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1798 &dlen
) == ERROR_SUCCESS
) {
1800 RegDeleteValueW(winkey
, valueW
);
1801 /* reset dlen and vlen */
1805 HeapFree(GetProcessHeap(), 0, data
);
1806 HeapFree(GetProcessHeap(), 0, valueW
);
1808 /* Delete the old external fonts key */
1809 RegCloseKey(externalkey
);
1811 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1813 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1814 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1815 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
1816 ERR("Can't create external font reg key\n");
1820 /* enumerate the fonts and add external ones to the two keys */
1822 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1823 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1824 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1825 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1826 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1827 if(!face
->external
) continue;
1829 if(strcmpiW(face
->StyleName
, RegularW
))
1830 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1831 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1832 strcpyW(valueW
, family
->FamilyName
);
1833 if(len
!= len_fam
) {
1834 strcatW(valueW
, spaceW
);
1835 strcatW(valueW
, face
->StyleName
);
1837 strcatW(valueW
, TrueType
);
1838 if((path
= strrchr(face
->file
, '/')) == NULL
)
1842 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1844 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1845 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1846 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1847 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1849 HeapFree(GetProcessHeap(), 0, file
);
1850 HeapFree(GetProcessHeap(), 0, valueW
);
1855 RegCloseKey(externalkey
);
1857 RegCloseKey(winkey
);
1862 /*************************************************************
1863 * WineEngAddFontResourceEx
1866 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1869 if (ft_handle
) /* do it only if we have freetype up and running */
1874 FIXME("Ignoring flags %x\n", flags
);
1876 if((unixname
= wine_get_unix_file_name(file
)))
1878 EnterCriticalSection( &freetype_cs
);
1879 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1880 LeaveCriticalSection( &freetype_cs
);
1881 HeapFree(GetProcessHeap(), 0, unixname
);
1883 if (!ret
&& !strchrW(file
, '\\')) {
1884 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
1885 ret
= load_font_from_winfonts_dir(file
);
1887 /* Try in datadir/fonts (or builddir/fonts),
1888 * needed for Magic the Gathering Online
1890 ret
= load_font_from_data_dir(file
);
1897 /*************************************************************
1898 * WineEngAddFontMemResourceEx
1901 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
1903 if (ft_handle
) /* do it only if we have freetype up and running */
1905 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
1907 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
1908 memcpy(pFontCopy
, pbFont
, cbFont
);
1910 EnterCriticalSection( &freetype_cs
);
1911 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1912 LeaveCriticalSection( &freetype_cs
);
1916 TRACE("AddFontToList failed\n");
1917 HeapFree(GetProcessHeap(), 0, pFontCopy
);
1920 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1921 * For now return something unique but quite random
1923 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
1924 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
1931 /*************************************************************
1932 * WineEngRemoveFontResourceEx
1935 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1941 static const struct nls_update_font_list
1943 UINT ansi_cp
, oem_cp
;
1944 const char *oem
, *fixed
, *system
;
1945 const char *courier
, *serif
, *small
, *sserif
;
1946 /* these are for font substitute */
1947 const char *shelldlg
, *tmsrmn
;
1948 } nls_update_font_list
[] =
1950 /* Latin 1 (United States) */
1951 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1952 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1953 "Tahoma","Times New Roman",
1955 /* Latin 1 (Multilingual) */
1956 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1957 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1958 "Tahoma","Times New Roman", /* FIXME unverified */
1960 /* Eastern Europe */
1961 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1962 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1963 "Tahoma","Times New Roman", /* FIXME unverified */
1966 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1967 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1968 "Tahoma","Times New Roman", /* FIXME unverified */
1971 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1972 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1973 "Tahoma","Times New Roman", /* FIXME unverified */
1976 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1977 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1978 "Tahoma","Times New Roman", /* FIXME unverified */
1981 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1982 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1983 "Tahoma","Times New Roman", /* FIXME unverified */
1986 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1987 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1988 "Tahoma","Times New Roman", /* FIXME unverified */
1991 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1992 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1993 "Tahoma","Times New Roman", /* FIXME unverified */
1996 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1997 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1998 "Tahoma","Times New Roman", /* FIXME unverified */
2001 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2002 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2003 "Tahoma","Times New Roman", /* FIXME unverified */
2006 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2007 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2008 "MS UI Gothic","MS Serif",
2010 /* Chinese Simplified */
2011 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2012 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2013 "Tahoma", "Times New Roman", /* FIXME unverified */
2016 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2017 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2020 /* Chinese Traditional */
2021 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2022 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2023 "PMingLiU", "MingLiU",
2027 static inline HKEY
create_fonts_NT_registry_key(void)
2031 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2032 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2036 static inline HKEY
create_fonts_9x_registry_key(void)
2040 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2041 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2045 static inline HKEY
create_config_fonts_registry_key(void)
2049 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2050 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2054 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2056 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2057 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2058 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2059 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2062 static void update_font_info(void)
2064 char buf
[40], cpbuf
[40];
2067 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2069 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2072 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2073 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2074 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2075 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2076 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2078 /* Setup DefaultFallback usage */
2080 use_default_fallback
= TRUE
;
2083 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2085 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2090 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2092 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2094 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2097 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2099 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2100 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2104 hkey
= create_config_fonts_registry_key();
2105 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2106 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2107 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2110 hkey
= create_fonts_NT_registry_key();
2111 add_font_list(hkey
, &nls_update_font_list
[i
]);
2114 hkey
= create_fonts_9x_registry_key();
2115 add_font_list(hkey
, &nls_update_font_list
[i
]);
2118 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2120 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2121 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2122 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2123 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2129 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2132 /*************************************************************
2135 * Initialize FreeType library and create a list of available faces
2137 BOOL
WineEngInit(void)
2139 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2140 static const WCHAR pathW
[] = {'P','a','t','h',0};
2142 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2144 WCHAR windowsdir
[MAX_PATH
];
2147 const char *data_dir
;
2151 /* update locale dependent font info in registry */
2154 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2157 "Wine cannot find the FreeType font library. To enable Wine to\n"
2158 "use TrueType fonts please install a version of FreeType greater than\n"
2159 "or equal to 2.0.5.\n"
2160 "http://www.freetype.org\n");
2164 #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;}
2166 LOAD_FUNCPTR(FT_Vector_Unit
)
2167 LOAD_FUNCPTR(FT_Done_Face
)
2168 LOAD_FUNCPTR(FT_Get_Char_Index
)
2169 LOAD_FUNCPTR(FT_Get_Module
)
2170 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2171 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2172 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2173 LOAD_FUNCPTR(FT_Init_FreeType
)
2174 LOAD_FUNCPTR(FT_Load_Glyph
)
2175 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2176 LOAD_FUNCPTR(FT_MulFix
)
2177 LOAD_FUNCPTR(FT_New_Face
)
2178 LOAD_FUNCPTR(FT_New_Memory_Face
)
2179 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2180 LOAD_FUNCPTR(FT_Outline_Transform
)
2181 LOAD_FUNCPTR(FT_Outline_Translate
)
2182 LOAD_FUNCPTR(FT_Select_Charmap
)
2183 LOAD_FUNCPTR(FT_Set_Charmap
)
2184 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2185 LOAD_FUNCPTR(FT_Vector_Transform
)
2188 /* Don't warn if this one is missing */
2189 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2190 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2191 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2192 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2193 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2194 #ifdef HAVE_FREETYPE_FTWINFNT_H
2195 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2197 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2198 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2199 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2200 <= 2.0.3 has FT_Sqrt64 */
2204 if(pFT_Init_FreeType(&library
) != 0) {
2205 ERR("Can't init FreeType library\n");
2206 wine_dlclose(ft_handle
, NULL
, 0);
2210 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
2211 if (pFT_Library_Version
)
2213 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2215 if (FT_Version
.major
<=0)
2221 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2222 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2223 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2224 ((FT_Version
.patch
) & 0x0000ff);
2226 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2227 ERR("Failed to create font mutex\n");
2230 WaitForSingleObject(font_mutex
, INFINITE
);
2232 /* load the system bitmap fonts */
2233 load_system_fonts();
2235 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2236 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2237 strcatW(windowsdir
, fontsW
);
2238 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2240 ReadFontDir(unixname
, FALSE
);
2241 HeapFree(GetProcessHeap(), 0, unixname
);
2244 /* load the system truetype fonts */
2245 data_dir
= wine_get_data_dir();
2246 if (!data_dir
) data_dir
= wine_get_build_dir();
2247 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2248 strcpy(unixname
, data_dir
);
2249 strcat(unixname
, "/fonts/");
2250 ReadFontDir(unixname
, TRUE
);
2251 HeapFree(GetProcessHeap(), 0, unixname
);
2254 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2255 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2256 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2258 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2259 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2260 &hkey
) == ERROR_SUCCESS
) {
2262 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2263 &valuelen
, &datalen
, NULL
, NULL
);
2265 valuelen
++; /* returned value doesn't include room for '\0' */
2266 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2267 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2270 dlen
= datalen
* sizeof(WCHAR
);
2272 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2273 &dlen
) == ERROR_SUCCESS
) {
2274 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2276 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2278 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2279 HeapFree(GetProcessHeap(), 0, unixname
);
2282 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2284 WCHAR pathW
[MAX_PATH
];
2285 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2288 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2289 if((unixname
= wine_get_unix_file_name(pathW
)))
2291 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2292 HeapFree(GetProcessHeap(), 0, unixname
);
2295 load_font_from_data_dir(data
);
2297 /* reset dlen and vlen */
2302 HeapFree(GetProcessHeap(), 0, data
);
2303 HeapFree(GetProcessHeap(), 0, valueW
);
2307 load_fontconfig_fonts();
2309 /* then look in any directories that we've specified in the config file */
2310 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2311 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2317 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2319 len
+= sizeof(WCHAR
);
2320 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2321 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2323 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2324 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2325 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2326 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2330 LPSTR next
= strchr( ptr
, ':' );
2331 if (next
) *next
++ = 0;
2332 ReadFontDir( ptr
, TRUE
);
2335 HeapFree( GetProcessHeap(), 0, valueA
);
2337 HeapFree( GetProcessHeap(), 0, valueW
);
2346 update_reg_entries();
2348 init_system_links();
2350 ReleaseMutex(font_mutex
);
2354 "Wine cannot find certain functions that it needs inside the FreeType\n"
2355 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2356 "FreeType to at least version 2.0.5.\n"
2357 "http://www.freetype.org\n");
2358 wine_dlclose(ft_handle
, NULL
, 0);
2364 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2367 TT_HoriHeader
*pHori
;
2371 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2372 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2374 if(height
== 0) height
= 16;
2376 /* Calc. height of EM square:
2378 * For +ve lfHeight we have
2379 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2380 * Re-arranging gives:
2381 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2383 * For -ve lfHeight we have
2385 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2386 * with il = winAscent + winDescent - units_per_em]
2391 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2392 ppem
= ft_face
->units_per_EM
* height
/
2393 (pHori
->Ascender
- pHori
->Descender
);
2395 ppem
= ft_face
->units_per_EM
* height
/
2396 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2404 static struct font_mapping
*map_font_file( const char *name
)
2406 struct font_mapping
*mapping
;
2410 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2411 if (fstat( fd
, &st
) == -1) goto error
;
2413 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2415 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2417 mapping
->refcount
++;
2422 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2425 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2428 if (mapping
->data
== MAP_FAILED
)
2430 HeapFree( GetProcessHeap(), 0, mapping
);
2433 mapping
->refcount
= 1;
2434 mapping
->dev
= st
.st_dev
;
2435 mapping
->ino
= st
.st_ino
;
2436 mapping
->size
= st
.st_size
;
2437 list_add_tail( &mappings_list
, &mapping
->entry
);
2445 static void unmap_font_file( struct font_mapping
*mapping
)
2447 if (!--mapping
->refcount
)
2449 list_remove( &mapping
->entry
);
2450 munmap( mapping
->data
, mapping
->size
);
2451 HeapFree( GetProcessHeap(), 0, mapping
);
2455 static LONG
load_VDMX(GdiFont
*, LONG
);
2457 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2464 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2468 if (!(font
->mapping
= map_font_file( face
->file
)))
2470 WARN("failed to map %s\n", debugstr_a(face
->file
));
2473 data_ptr
= font
->mapping
->data
;
2474 data_size
= font
->mapping
->size
;
2478 data_ptr
= face
->font_data_ptr
;
2479 data_size
= face
->font_data_size
;
2482 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2484 ERR("FT_New_Face rets %d\n", err
);
2488 /* set it here, as load_VDMX needs it */
2489 font
->ft_face
= ft_face
;
2491 if(FT_IS_SCALABLE(ft_face
)) {
2492 /* load the VDMX table if we have one */
2493 font
->ppem
= load_VDMX(font
, height
);
2495 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2497 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2498 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2500 font
->ppem
= height
;
2501 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2502 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2508 static int get_nearest_charset(Face
*face
, int *cp
)
2510 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2511 a single face with the requested charset. The idea is to check if
2512 the selected font supports the current ANSI codepage, if it does
2513 return the corresponding charset, else return the first charset */
2516 int acp
= GetACP(), i
;
2520 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2521 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2522 return csi
.ciCharset
;
2524 for(i
= 0; i
< 32; i
++) {
2526 if(face
->fs
.fsCsb
[0] & fs0
) {
2527 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2529 return csi
.ciCharset
;
2532 FIXME("TCI failing on %x\n", fs0
);
2536 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2537 face
->fs
.fsCsb
[0], face
->file
);
2539 return DEFAULT_CHARSET
;
2542 static GdiFont
*alloc_font(void)
2544 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2546 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2547 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2549 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2550 ret
->total_kern_pairs
= (DWORD
)-1;
2551 ret
->kern_pairs
= NULL
;
2552 list_init(&ret
->hfontlist
);
2553 list_init(&ret
->child_fonts
);
2557 static void free_font(GdiFont
*font
)
2559 struct list
*cursor
, *cursor2
;
2562 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2564 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2565 struct list
*first_hfont
;
2566 HFONTLIST
*hfontlist
;
2567 list_remove(cursor
);
2570 first_hfont
= list_head(&child
->font
->hfontlist
);
2571 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2572 DeleteObject(hfontlist
->hfont
);
2573 HeapFree(GetProcessHeap(), 0, hfontlist
);
2574 free_font(child
->font
);
2576 HeapFree(GetProcessHeap(), 0, child
);
2579 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2580 if (font
->mapping
) unmap_font_file( font
->mapping
);
2581 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2582 HeapFree(GetProcessHeap(), 0, font
->potm
);
2583 HeapFree(GetProcessHeap(), 0, font
->name
);
2584 for (i
= 0; i
< font
->gmsize
; i
++)
2585 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2586 HeapFree(GetProcessHeap(), 0, font
->gm
);
2587 HeapFree(GetProcessHeap(), 0, font
);
2591 /*************************************************************
2594 * load the vdmx entry for the specified height
2597 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2598 ( ( (FT_ULong)_x4 << 24 ) | \
2599 ( (FT_ULong)_x3 << 16 ) | \
2600 ( (FT_ULong)_x2 << 8 ) | \
2603 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2618 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2622 BYTE devXRatio
, devYRatio
;
2623 USHORT numRecs
, numRatios
;
2624 DWORD result
, offset
= -1;
2628 /* For documentation on VDMX records, see
2629 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2632 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2634 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2637 /* FIXME: need the real device aspect ratio */
2641 numRecs
= GET_BE_WORD(hdr
[1]);
2642 numRatios
= GET_BE_WORD(hdr
[2]);
2644 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2645 for(i
= 0; i
< numRatios
; i
++) {
2648 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2649 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2652 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2654 if((ratio
.xRatio
== 0 &&
2655 ratio
.yStartRatio
== 0 &&
2656 ratio
.yEndRatio
== 0) ||
2657 (devXRatio
== ratio
.xRatio
&&
2658 devYRatio
>= ratio
.yStartRatio
&&
2659 devYRatio
<= ratio
.yEndRatio
))
2661 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2662 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2663 offset
= GET_BE_WORD(tmp
);
2669 FIXME("No suitable ratio found\n");
2673 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2675 BYTE startsz
, endsz
;
2678 recs
= GET_BE_WORD(group
.recs
);
2679 startsz
= group
.startsz
;
2680 endsz
= group
.endsz
;
2682 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2684 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2685 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2686 if(result
== GDI_ERROR
) {
2687 FIXME("Failed to retrieve vTable\n");
2692 for(i
= 0; i
< recs
; i
++) {
2693 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2694 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2695 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2697 if(yMax
+ -yMin
== height
) {
2700 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2703 if(yMax
+ -yMin
> height
) {
2706 goto end
; /* failed */
2708 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2709 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2710 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2711 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2717 TRACE("ppem not found for height %d\n", height
);
2721 if(ppem
< startsz
|| ppem
> endsz
)
2724 for(i
= 0; i
< recs
; i
++) {
2726 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2728 if(yPelHeight
> ppem
)
2731 if(yPelHeight
== ppem
) {
2732 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2733 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2734 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2740 HeapFree(GetProcessHeap(), 0, vTable
);
2746 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
2748 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2749 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2750 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2751 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2752 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2755 static void calc_hash(FONT_DESC
*pfd
)
2757 DWORD hash
= 0, *ptr
, two_chars
;
2761 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2763 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2765 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2767 pwc
= (WCHAR
*)&two_chars
;
2769 *pwc
= toupperW(*pwc
);
2771 *pwc
= toupperW(*pwc
);
2775 hash
^= !pfd
->can_use_bitmap
;
2780 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2785 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2787 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
2788 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2789 fd
.can_use_bitmap
= can_use_bitmap
;
2792 /* try the in-use list */
2793 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2794 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2795 if(!fontcmp(ret
, &fd
)) {
2796 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2797 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2798 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2799 if(hflist
->hfont
== hfont
)
2802 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2803 hflist
->hfont
= hfont
;
2804 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2809 /* then the unused list */
2810 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2811 while(font_elem_ptr
) {
2812 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2813 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2814 if(!fontcmp(ret
, &fd
)) {
2815 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2816 assert(list_empty(&ret
->hfontlist
));
2817 TRACE("Found %p in unused list\n", ret
);
2818 list_remove(&ret
->entry
);
2819 list_add_head(&gdi_font_list
, &ret
->entry
);
2820 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2821 hflist
->hfont
= hfont
;
2822 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2830 /*************************************************************
2831 * create_child_font_list
2833 static BOOL
create_child_font_list(GdiFont
*font
)
2836 SYSTEM_LINKS
*font_link
;
2837 CHILD_FONT
*font_link_entry
, *new_child
;
2839 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2841 if(!strcmpW(font_link
->font_name
, font
->name
))
2843 TRACE("found entry in system list\n");
2844 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2846 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2847 new_child
->face
= font_link_entry
->face
;
2848 new_child
->font
= NULL
;
2849 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2850 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
2857 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2858 * Sans Serif. This is how asian windows get default fallbacks for fonts
2860 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
2861 font
->charset
!= OEM_CHARSET
&&
2862 strcmpW(font
->name
,szDefaultFallbackLink
) != 0)
2863 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2865 if(!strcmpW(font_link
->font_name
,szDefaultFallbackLink
))
2867 TRACE("found entry in default fallback list\n");
2868 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2870 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2871 new_child
->face
= font_link_entry
->face
;
2872 new_child
->font
= NULL
;
2873 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2874 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
2884 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2886 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2888 if (pFT_Set_Charmap
)
2891 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2893 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2895 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2897 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2899 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2900 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2902 switch (ft_face
->charmaps
[i
]->platform_id
)
2905 cmap_def
= ft_face
->charmaps
[i
];
2907 case 0: /* Apple Unicode */
2908 cmap0
= ft_face
->charmaps
[i
];
2910 case 1: /* Macintosh */
2911 cmap1
= ft_face
->charmaps
[i
];
2914 cmap2
= ft_face
->charmaps
[i
];
2916 case 3: /* Microsoft */
2917 cmap3
= ft_face
->charmaps
[i
];
2922 if (cmap3
) /* prefer Microsoft cmap table */
2923 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2925 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2927 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2929 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2931 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2933 return ft_err
== FT_Err_Ok
;
2936 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
2939 /*************************************************************
2940 * WineEngCreateFontInstance
2943 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2946 Face
*face
, *best
, *best_bitmap
;
2947 Family
*family
, *last_resort_family
;
2948 struct list
*family_elem_ptr
, *face_elem_ptr
;
2949 INT height
, width
= 0;
2950 unsigned int score
= 0, new_score
;
2951 signed int diff
= 0, newdiff
;
2952 BOOL bd
, it
, can_use_bitmap
;
2957 EnterCriticalSection( &freetype_cs
);
2959 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2961 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2962 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2963 if(hflist
->hfont
== hfont
)
2965 LeaveCriticalSection( &freetype_cs
);
2970 if (!GetObjectW( hfont
, sizeof(lf
), &lf
))
2972 LeaveCriticalSection( &freetype_cs
);
2975 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2977 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2978 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2979 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2982 /* check the cache first */
2983 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2984 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2985 LeaveCriticalSection( &freetype_cs
);
2989 TRACE("not in cache\n");
2990 if(list_empty(&font_list
)) /* No fonts installed */
2992 TRACE("No fonts installed\n");
2993 LeaveCriticalSection( &freetype_cs
);
2996 if(!have_installed_roman_font
)
2998 TRACE("No roman font installed\n");
2999 LeaveCriticalSection( &freetype_cs
);
3005 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3006 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
3007 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3008 calc_hash(&ret
->font_desc
);
3009 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3010 hflist
->hfont
= hfont
;
3011 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3014 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3015 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3016 original value lfCharSet. Note this is a special case for
3017 Symbol and doesn't happen at least for "Wingdings*" */
3019 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3020 lf
.lfCharSet
= SYMBOL_CHARSET
;
3022 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3023 switch(lf
.lfCharSet
) {
3024 case DEFAULT_CHARSET
:
3025 csi
.fs
.fsCsb
[0] = 0;
3028 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3029 csi
.fs
.fsCsb
[0] = 0;
3035 if(lf
.lfFaceName
[0] != '\0') {
3037 SYSTEM_LINKS
*font_link
;
3038 CHILD_FONT
*font_link_entry
;
3040 psub
= get_font_subst(&font_subst_list
, lf
.lfFaceName
, lf
.lfCharSet
);
3043 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
3044 debugstr_w(psub
->to
.name
));
3045 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3048 /* We want a match on name and charset or just name if
3049 charset was DEFAULT_CHARSET. If the latter then
3050 we fixup the returned charset later in get_nearest_charset
3051 where we'll either use the charset of the current ansi codepage
3052 or if that's unavailable the first charset that the font supports.
3054 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3055 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3056 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3057 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3058 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3059 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3060 if(face
->scalable
|| can_use_bitmap
)
3067 * Try check the SystemLink list first for a replacement font.
3068 * We may find good replacements there.
3070 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3072 if(!strcmpiW(font_link
->font_name
, lf
.lfFaceName
))
3074 TRACE("found entry in system list\n");
3075 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3077 face
= font_link_entry
->face
;
3078 family
= face
->family
;
3079 if(csi
.fs
.fsCsb
[0] &
3080 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3082 if(face
->scalable
|| can_use_bitmap
)
3090 /* If requested charset was DEFAULT_CHARSET then try using charset
3091 corresponding to the current ansi codepage */
3092 if(!csi
.fs
.fsCsb
[0]) {
3094 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3095 FIXME("TCI failed on codepage %d\n", acp
);
3096 csi
.fs
.fsCsb
[0] = 0;
3098 lf
.lfCharSet
= csi
.ciCharset
;
3101 /* Face families are in the top 4 bits of lfPitchAndFamily,
3102 so mask with 0xF0 before testing */
3104 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3105 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3106 strcpyW(lf
.lfFaceName
, defFixed
);
3107 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3108 strcpyW(lf
.lfFaceName
, defSerif
);
3109 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3110 strcpyW(lf
.lfFaceName
, defSans
);
3112 strcpyW(lf
.lfFaceName
, defSans
);
3113 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3114 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3115 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3116 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3117 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3118 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3119 if(face
->scalable
|| can_use_bitmap
)
3125 last_resort_family
= NULL
;
3126 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3127 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3128 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3129 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3130 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3133 if(can_use_bitmap
&& !last_resort_family
)
3134 last_resort_family
= family
;
3139 if(last_resort_family
) {
3140 family
= last_resort_family
;
3141 csi
.fs
.fsCsb
[0] = 0;
3145 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3146 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3147 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3148 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3149 if(face
->scalable
) {
3150 csi
.fs
.fsCsb
[0] = 0;
3151 WARN("just using first face for now\n");
3154 if(can_use_bitmap
&& !last_resort_family
)
3155 last_resort_family
= family
;
3158 if(!last_resort_family
) {
3159 FIXME("can't find a single appropriate font - bailing\n");
3161 LeaveCriticalSection( &freetype_cs
);
3165 WARN("could only find a bitmap font - this will probably look awful!\n");
3166 family
= last_resort_family
;
3167 csi
.fs
.fsCsb
[0] = 0;
3170 it
= lf
.lfItalic
? 1 : 0;
3171 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3173 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
3174 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
3176 face
= best
= best_bitmap
= NULL
;
3177 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3179 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3181 new_score
= (face
->Italic
^ it
) + (face
->Bold
^ bd
);
3182 if(!best
|| new_score
<= score
)
3184 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3185 face
->Italic
, face
->Bold
, it
, bd
);
3188 if(best
->scalable
&& score
== 0) break;
3192 newdiff
= height
- (signed int)(best
->size
.height
);
3194 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3195 if(!best_bitmap
|| new_score
< score
||
3196 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3198 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3201 if(score
== 0 && diff
== 0) break;
3208 face
= best
->scalable
? best
: best_bitmap
;
3209 ret
->fake_italic
= (it
&& !face
->Italic
);
3210 ret
->fake_bold
= (bd
&& !face
->Bold
);
3212 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
3214 if(csi
.fs
.fsCsb
[0]) {
3215 ret
->charset
= lf
.lfCharSet
;
3216 ret
->codepage
= csi
.ciACP
;
3219 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3221 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3222 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3224 ret
->aveWidth
= abs(lf
.lfWidth
);
3226 if(!face
->scalable
) {
3227 /* Windows uses integer scaling factors for bitmap fonts */
3228 INT scale
, scaled_height
;
3230 if (height
!= 0) height
= diff
;
3232 height
+= face
->size
.height
;
3234 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3235 scaled_height
= scale
* face
->size
.height
;
3236 /* XP allows not more than 10% deviation */
3237 if (scale
> 1 && scaled_height
- height
> scaled_height
/ 10) scale
--;
3238 ret
->scale_y
= scale
;
3240 width
= face
->size
.x_ppem
>> 6;
3241 height
= face
->size
.y_ppem
>> 6;
3245 TRACE("font scale y: %f\n", ret
->scale_y
);
3247 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3252 LeaveCriticalSection( &freetype_cs
);
3256 ret
->ntmFlags
= face
->ntmFlags
;
3258 if (ret
->charset
== SYMBOL_CHARSET
&&
3259 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3262 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3266 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3269 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3270 ret
->name
= strdupW(family
->FamilyName
);
3271 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3272 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3273 create_child_font_list(ret
);
3275 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3277 list_add_head(&gdi_font_list
, &ret
->entry
);
3278 LeaveCriticalSection( &freetype_cs
);
3282 static void dump_gdi_font_list(void)
3285 struct list
*elem_ptr
;
3287 TRACE("---------- gdiFont Cache ----------\n");
3288 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3289 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3290 TRACE("gdiFont=%p %s %d\n",
3291 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3294 TRACE("---------- Unused gdiFont Cache ----------\n");
3295 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3296 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3297 TRACE("gdiFont=%p %s %d\n",
3298 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3302 /*************************************************************
3303 * WineEngDestroyFontInstance
3305 * free the gdiFont associated with this handle
3308 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3313 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3316 EnterCriticalSection( &freetype_cs
);
3318 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3320 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3321 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3322 if(hflist
->hfont
== handle
)
3324 TRACE("removing child font %p from child list\n", gdiFont
);
3325 list_remove(&gdiFont
->entry
);
3326 LeaveCriticalSection( &freetype_cs
);
3331 TRACE("destroying hfont=%p\n", handle
);
3333 dump_gdi_font_list();
3335 font_elem_ptr
= list_head(&gdi_font_list
);
3336 while(font_elem_ptr
) {
3337 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3338 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3340 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3341 while(hfontlist_elem_ptr
) {
3342 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3343 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3344 if(hflist
->hfont
== handle
) {
3345 list_remove(&hflist
->entry
);
3346 HeapFree(GetProcessHeap(), 0, hflist
);
3350 if(list_empty(&gdiFont
->hfontlist
)) {
3351 TRACE("Moving to Unused list\n");
3352 list_remove(&gdiFont
->entry
);
3353 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3358 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3359 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3360 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3361 while(font_elem_ptr
) {
3362 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3363 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3364 TRACE("freeing %p\n", gdiFont
);
3365 list_remove(&gdiFont
->entry
);
3368 LeaveCriticalSection( &freetype_cs
);
3372 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3373 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3378 if (face
->cached_enum_data
)
3381 memcpy(pelf
, &face
->cached_enum_data
->elf
, sizeof(ENUMLOGFONTEXW
));
3382 memcpy(pntm
, &face
->cached_enum_data
->ntm
, sizeof(NEWTEXTMETRICEXW
));
3383 *ptype
= face
->cached_enum_data
->type
;
3387 font
= alloc_font();
3389 if(face
->scalable
) {
3393 height
= face
->size
.y_ppem
>> 6;
3394 width
= face
->size
.x_ppem
>> 6;
3396 font
->scale_y
= 1.0;
3398 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3404 font
->name
= strdupW(face
->family
->FamilyName
);
3405 font
->ntmFlags
= face
->ntmFlags
;
3407 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3409 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3411 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3413 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3414 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3416 lstrcpynW(pelf
->elfFullName
,
3417 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
3419 lstrcpynW(pelf
->elfStyle
,
3420 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
3425 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
3427 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3429 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3430 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
3431 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
3434 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
3435 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3436 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3437 memcpy(&pntm
->ntmFontSig
, &face
->fs
, sizeof(FONTSIGNATURE
));
3439 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3441 pelf
->elfLogFont
.lfEscapement
= 0;
3442 pelf
->elfLogFont
.lfOrientation
= 0;
3443 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
3444 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3445 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
3446 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
3447 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
3448 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
3449 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
3450 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3451 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3452 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3453 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3456 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
3457 *ptype
|= TRUETYPE_FONTTYPE
;
3458 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
3459 *ptype
|= DEVICE_FONTTYPE
;
3460 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
3461 *ptype
|= RASTER_FONTTYPE
;
3463 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
3464 if (face
->cached_enum_data
)
3466 memcpy(&face
->cached_enum_data
->elf
, pelf
, sizeof(ENUMLOGFONTEXW
));
3467 memcpy(&face
->cached_enum_data
->ntm
, pntm
, sizeof(NEWTEXTMETRICEXW
));
3468 face
->cached_enum_data
->type
= *ptype
;
3474 /*************************************************************
3478 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3482 struct list
*family_elem_ptr
, *face_elem_ptr
;
3484 NEWTEXTMETRICEXW ntm
;
3493 lf
.lfCharSet
= DEFAULT_CHARSET
;
3494 lf
.lfPitchAndFamily
= 0;
3495 lf
.lfFaceName
[0] = 0;
3499 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3501 EnterCriticalSection( &freetype_cs
);
3502 if(plf
->lfFaceName
[0]) {
3504 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3507 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3508 debugstr_w(psub
->to
.name
));
3509 memcpy(&lf
, plf
, sizeof(lf
));
3510 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3514 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3515 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3516 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3517 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3518 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3519 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3520 for(i
= 0; i
< 32; i
++) {
3521 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3522 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3523 strcpyW(elf
.elfScript
, OEM_DOSW
);
3524 i
= 32; /* break out of loop */
3525 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3528 fs
.fsCsb
[0] = 1L << i
;
3530 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3532 csi
.ciCharset
= DEFAULT_CHARSET
;
3533 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3534 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3535 elf
.elfLogFont
.lfCharSet
=
3536 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3538 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3540 FIXME("Unknown elfscript for bit %d\n", i
);
3543 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3544 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3545 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3546 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3547 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3548 ntm
.ntmTm
.ntmFlags
);
3549 /* release section before callback (FIXME) */
3550 LeaveCriticalSection( &freetype_cs
);
3551 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3552 EnterCriticalSection( &freetype_cs
);
3558 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3559 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3560 face_elem_ptr
= list_head(&family
->faces
);
3561 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3562 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3563 for(i
= 0; i
< 32; i
++) {
3564 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3565 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3566 strcpyW(elf
.elfScript
, OEM_DOSW
);
3567 i
= 32; /* break out of loop */
3568 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3571 fs
.fsCsb
[0] = 1L << i
;
3573 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3575 csi
.ciCharset
= DEFAULT_CHARSET
;
3576 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3577 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3578 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3581 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3583 FIXME("Unknown elfscript for bit %d\n", i
);
3586 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3587 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3588 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3589 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3590 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3591 ntm
.ntmTm
.ntmFlags
);
3592 /* release section before callback (FIXME) */
3593 LeaveCriticalSection( &freetype_cs
);
3594 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3595 EnterCriticalSection( &freetype_cs
);
3599 LeaveCriticalSection( &freetype_cs
);
3603 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3605 pt
->x
.value
= vec
->x
>> 6;
3606 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3607 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3608 pt
->y
.value
= vec
->y
>> 6;
3609 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3610 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3614 /***************************************************
3615 * According to the MSDN documentation on WideCharToMultiByte,
3616 * certain codepages cannot set the default_used parameter.
3617 * This returns TRUE if the codepage can set that parameter, false else
3618 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3620 static BOOL
codepage_sets_default_used(UINT codepage
)
3633 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
3635 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
3636 WCHAR wc
= (WCHAR
)glyph
;
3638 BOOL
*default_used_pointer
;
3641 default_used_pointer
= NULL
;
3642 default_used
= FALSE
;
3643 if (codepage_sets_default_used(font
->codepage
))
3644 default_used_pointer
= &default_used
;
3645 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
3648 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
3649 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
3653 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
3654 glyph
= glyph
+ 0xf000;
3655 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
3658 /*************************************************************
3659 * WineEngGetGlyphIndices
3661 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3663 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
3664 LPWORD pgi
, DWORD flags
)
3667 WCHAR default_char
= 0;
3670 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0x001f; /* Indicate non existence */
3672 for(i
= 0; i
< count
; i
++)
3674 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
3679 WineEngGetTextMetrics(font
, &textm
);
3680 default_char
= textm
.tmDefaultChar
;
3682 pgi
[i
] = default_char
;
3688 /*************************************************************
3689 * WineEngGetGlyphOutline
3691 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3692 * except that the first parameter is the HWINEENGFONT of the font in
3693 * question rather than an HDC.
3696 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
3697 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3700 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
3701 FT_Face ft_face
= incoming_font
->ft_face
;
3702 GdiFont
*font
= incoming_font
;
3703 FT_UInt glyph_index
;
3704 DWORD width
, height
, pitch
, needed
= 0;
3705 FT_Bitmap ft_bitmap
;
3707 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
3709 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3710 float widthRatio
= 1.0;
3711 FT_Matrix transMat
= identityMat
;
3712 BOOL needsTransform
= FALSE
;
3715 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
3716 buflen
, buf
, lpmat
);
3718 EnterCriticalSection( &freetype_cs
);
3720 if(format
& GGO_GLYPH_INDEX
) {
3721 glyph_index
= glyph
;
3722 format
&= ~GGO_GLYPH_INDEX
;
3724 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
3725 ft_face
= font
->ft_face
;
3728 if(glyph_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
3729 font
->gmsize
= (glyph_index
/ GM_BLOCK_SIZE
+ 1);
3730 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
3731 font
->gmsize
* sizeof(GM
*));
3733 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] != NULL
&& FONT_GM(font
,glyph_index
)->init
) {
3734 *lpgm
= FONT_GM(font
,glyph_index
)->gm
;
3735 LeaveCriticalSection( &freetype_cs
);
3736 return 1; /* FIXME */
3740 if (!font
->gm
[glyph_index
/ GM_BLOCK_SIZE
])
3741 font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3743 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) || lpmat
)
3744 load_flags
|= FT_LOAD_NO_BITMAP
;
3746 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
3749 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
3750 LeaveCriticalSection( &freetype_cs
);
3754 /* Scaling factor */
3755 if (font
->aveWidth
&& font
->potm
)
3757 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
3758 widthRatio
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
3761 widthRatio
= font
->scale_y
;
3763 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
3764 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
3766 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
3768 bbx
= (right
- left
) >> 6;
3770 /* Scaling transform */
3771 if(font
->aveWidth
) {
3773 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
3776 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
3778 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
3779 needsTransform
= TRUE
;
3782 /* Slant transform */
3783 if (font
->fake_italic
) {
3786 slantMat
.xx
= (1 << 16);
3787 slantMat
.xy
= ((1 << 16) >> 2);
3789 slantMat
.yy
= (1 << 16);
3790 pFT_Matrix_Multiply(&slantMat
, &transMat
);
3791 needsTransform
= TRUE
;
3794 /* Rotation transform */
3795 if(font
->orientation
) {
3796 FT_Matrix rotationMat
;
3798 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
3799 pFT_Vector_Unit(&vecAngle
, angle
);
3800 rotationMat
.xx
= vecAngle
.x
;
3801 rotationMat
.xy
= -vecAngle
.y
;
3802 rotationMat
.yx
= -rotationMat
.xy
;
3803 rotationMat
.yy
= rotationMat
.xx
;
3805 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
3806 needsTransform
= TRUE
;
3809 /* Extra transformation specified by caller */
3812 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
3813 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
3814 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
3815 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
3816 pFT_Matrix_Multiply(&extraMat
, &transMat
);
3817 needsTransform
= TRUE
;
3820 if(!needsTransform
) {
3821 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
3822 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
3823 ft_face
->glyph
->metrics
.height
) & -64;
3824 lpgm
->gmCellIncX
= adv
;
3825 lpgm
->gmCellIncY
= 0;
3829 for(xc
= 0; xc
< 2; xc
++) {
3830 for(yc
= 0; yc
< 2; yc
++) {
3831 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
3832 xc
* ft_face
->glyph
->metrics
.width
);
3833 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
3834 yc
* ft_face
->glyph
->metrics
.height
;
3835 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
3836 pFT_Vector_Transform(&vec
, &transMat
);
3837 if(xc
== 0 && yc
== 0) {
3838 left
= right
= vec
.x
;
3839 top
= bottom
= vec
.y
;
3841 if(vec
.x
< left
) left
= vec
.x
;
3842 else if(vec
.x
> right
) right
= vec
.x
;
3843 if(vec
.y
< bottom
) bottom
= vec
.y
;
3844 else if(vec
.y
> top
) top
= vec
.y
;
3849 right
= (right
+ 63) & -64;
3850 bottom
= bottom
& -64;
3851 top
= (top
+ 63) & -64;
3853 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
3854 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
3856 pFT_Vector_Transform(&vec
, &transMat
);
3857 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
3858 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
3860 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
3861 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
3862 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
3863 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
3865 if(format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
)
3867 FONT_GM(font
,glyph_index
)->gm
= *lpgm
;
3868 FONT_GM(font
,glyph_index
)->adv
= adv
;
3869 FONT_GM(font
,glyph_index
)->lsb
= lsb
;
3870 FONT_GM(font
,glyph_index
)->bbx
= bbx
;
3871 FONT_GM(font
,glyph_index
)->init
= TRUE
;
3874 if(format
== GGO_METRICS
)
3876 LeaveCriticalSection( &freetype_cs
);
3877 return 1; /* FIXME */
3880 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) {
3881 TRACE("loaded a bitmap\n");
3882 LeaveCriticalSection( &freetype_cs
);
3888 width
= lpgm
->gmBlackBoxX
;
3889 height
= lpgm
->gmBlackBoxY
;
3890 pitch
= ((width
+ 31) >> 5) << 2;
3891 needed
= pitch
* height
;
3893 if(!buf
|| !buflen
) break;
3895 switch(ft_face
->glyph
->format
) {
3896 case ft_glyph_format_bitmap
:
3898 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3899 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
3900 INT h
= ft_face
->glyph
->bitmap
.rows
;
3902 memcpy(dst
, src
, w
);
3903 src
+= ft_face
->glyph
->bitmap
.pitch
;
3909 case ft_glyph_format_outline
:
3910 ft_bitmap
.width
= width
;
3911 ft_bitmap
.rows
= height
;
3912 ft_bitmap
.pitch
= pitch
;
3913 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
3914 ft_bitmap
.buffer
= buf
;
3916 if(needsTransform
) {
3917 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3920 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3922 /* Note: FreeType will only set 'black' bits for us. */
3923 memset(buf
, 0, needed
);
3924 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3928 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3929 LeaveCriticalSection( &freetype_cs
);
3934 case GGO_GRAY2_BITMAP
:
3935 case GGO_GRAY4_BITMAP
:
3936 case GGO_GRAY8_BITMAP
:
3937 case WINE_GGO_GRAY16_BITMAP
:
3939 unsigned int mult
, row
, col
;
3942 width
= lpgm
->gmBlackBoxX
;
3943 height
= lpgm
->gmBlackBoxY
;
3944 pitch
= (width
+ 3) / 4 * 4;
3945 needed
= pitch
* height
;
3947 if(!buf
|| !buflen
) break;
3949 switch(ft_face
->glyph
->format
) {
3950 case ft_glyph_format_bitmap
:
3952 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3953 INT h
= ft_face
->glyph
->bitmap
.rows
;
3956 for(x
= 0; x
< pitch
; x
++)
3957 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
3958 src
+= ft_face
->glyph
->bitmap
.pitch
;
3961 LeaveCriticalSection( &freetype_cs
);
3964 case ft_glyph_format_outline
:
3966 ft_bitmap
.width
= width
;
3967 ft_bitmap
.rows
= height
;
3968 ft_bitmap
.pitch
= pitch
;
3969 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
3970 ft_bitmap
.buffer
= buf
;
3973 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3975 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3977 memset(ft_bitmap
.buffer
, 0, buflen
);
3979 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3981 if(format
== GGO_GRAY2_BITMAP
)
3983 else if(format
== GGO_GRAY4_BITMAP
)
3985 else if(format
== GGO_GRAY8_BITMAP
)
3987 else /* format == WINE_GGO_GRAY16_BITMAP */
3989 LeaveCriticalSection( &freetype_cs
);
3995 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3996 LeaveCriticalSection( &freetype_cs
);
4001 for(row
= 0; row
< height
; row
++) {
4003 for(col
= 0; col
< width
; col
++, ptr
++) {
4004 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4013 int contour
, point
= 0, first_pt
;
4014 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4015 TTPOLYGONHEADER
*pph
;
4017 DWORD pph_start
, cpfx
, type
;
4019 if(buflen
== 0) buf
= NULL
;
4021 if (needsTransform
&& buf
) {
4022 pFT_Outline_Transform(outline
, &transMat
);
4025 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4027 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4030 pph
->dwType
= TT_POLYGON_TYPE
;
4031 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4033 needed
+= sizeof(*pph
);
4035 while(point
<= outline
->contours
[contour
]) {
4036 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4037 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4038 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
4042 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4045 } while(point
<= outline
->contours
[contour
] &&
4046 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4047 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4048 /* At the end of a contour Windows adds the start point, but
4050 if(point
> outline
->contours
[contour
] &&
4051 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4053 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
4055 } else if(point
<= outline
->contours
[contour
] &&
4056 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4057 /* add closing pt for bezier */
4059 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4067 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4070 pph
->cb
= needed
- pph_start
;
4076 /* Convert the quadratic Beziers to cubic Beziers.
4077 The parametric eqn for a cubic Bezier is, from PLRM:
4078 r(t) = at^3 + bt^2 + ct + r0
4079 with the control points:
4084 A quadratic Beizer has the form:
4085 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4087 So equating powers of t leads to:
4088 r1 = 2/3 p1 + 1/3 p0
4089 r2 = 2/3 p1 + 1/3 p2
4090 and of course r0 = p0, r3 = p2
4093 int contour
, point
= 0, first_pt
;
4094 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4095 TTPOLYGONHEADER
*pph
;
4097 DWORD pph_start
, cpfx
, type
;
4098 FT_Vector cubic_control
[4];
4099 if(buflen
== 0) buf
= NULL
;
4101 if (needsTransform
&& buf
) {
4102 pFT_Outline_Transform(outline
, &transMat
);
4105 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4107 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4110 pph
->dwType
= TT_POLYGON_TYPE
;
4111 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4113 needed
+= sizeof(*pph
);
4115 while(point
<= outline
->contours
[contour
]) {
4116 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4117 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4118 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
4121 if(type
== TT_PRIM_LINE
) {
4123 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4127 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4130 /* FIXME: Possible optimization in endpoint calculation
4131 if there are two consecutive curves */
4132 cubic_control
[0] = outline
->points
[point
-1];
4133 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4134 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
4135 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
4136 cubic_control
[0].x
>>= 1;
4137 cubic_control
[0].y
>>= 1;
4139 if(point
+1 > outline
->contours
[contour
])
4140 cubic_control
[3] = outline
->points
[first_pt
];
4142 cubic_control
[3] = outline
->points
[point
+1];
4143 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
4144 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
4145 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
4146 cubic_control
[3].x
>>= 1;
4147 cubic_control
[3].y
>>= 1;
4150 /* r1 = 1/3 p0 + 2/3 p1
4151 r2 = 1/3 p2 + 2/3 p1 */
4152 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
4153 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
4154 cubic_control
[2] = cubic_control
[1];
4155 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
4156 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
4157 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
4158 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
4160 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
4161 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
4162 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
4167 } while(point
<= outline
->contours
[contour
] &&
4168 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4169 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4170 /* At the end of a contour Windows adds the start point,
4171 but only for Beziers and we've already done that.
4173 if(point
<= outline
->contours
[contour
] &&
4174 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4175 /* This is the closing pt of a bezier, but we've already
4176 added it, so just inc point and carry on */
4183 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4186 pph
->cb
= needed
- pph_start
;
4192 FIXME("Unsupported format %d\n", format
);
4193 LeaveCriticalSection( &freetype_cs
);
4196 LeaveCriticalSection( &freetype_cs
);
4200 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
4202 FT_Face ft_face
= font
->ft_face
;
4203 #ifdef HAVE_FREETYPE_FTWINFNT_H
4204 FT_WinFNT_HeaderRec winfnt_header
;
4206 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
4207 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
4208 font
->potm
->otmSize
= size
;
4210 #define TM font->potm->otmTextMetrics
4211 #ifdef HAVE_FREETYPE_FTWINFNT_H
4212 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
4214 TM
.tmHeight
= winfnt_header
.pixel_height
;
4215 TM
.tmAscent
= winfnt_header
.ascent
;
4216 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
4217 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
4218 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
4219 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
4220 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4221 TM
.tmWeight
= winfnt_header
.weight
;
4223 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4224 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4225 TM
.tmFirstChar
= winfnt_header
.first_char
;
4226 TM
.tmLastChar
= winfnt_header
.last_char
;
4227 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4228 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4229 TM
.tmItalic
= winfnt_header
.italic
;
4230 TM
.tmUnderlined
= font
->underline
;
4231 TM
.tmStruckOut
= font
->strikeout
;
4232 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4233 TM
.tmCharSet
= winfnt_header
.charset
;
4238 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4239 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4240 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4241 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4242 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4243 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4244 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4245 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4247 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4248 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4250 TM
.tmLastChar
= 255;
4251 TM
.tmDefaultChar
= 32;
4252 TM
.tmBreakChar
= 32;
4253 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4254 TM
.tmUnderlined
= font
->underline
;
4255 TM
.tmStruckOut
= font
->strikeout
;
4256 /* NB inverted meaning of TMPF_FIXED_PITCH */
4257 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4258 TM
.tmCharSet
= font
->charset
;
4266 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
4272 scale_x
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
4273 scale_x
/= (float)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4276 scale_x
= font
->scale_y
;
4278 ptm
->tmHeight
= (float)ptm
->tmHeight
* font
->scale_y
;
4279 ptm
->tmAscent
= (float)ptm
->tmAscent
* font
->scale_y
;
4280 ptm
->tmDescent
= (float)ptm
->tmDescent
* font
->scale_y
;
4281 ptm
->tmInternalLeading
= (float)ptm
->tmInternalLeading
* font
->scale_y
;
4282 ptm
->tmExternalLeading
= (float)ptm
->tmExternalLeading
* font
->scale_y
;
4284 ptm
->tmAveCharWidth
= (float)ptm
->tmAveCharWidth
* scale_x
;
4285 ptm
->tmMaxCharWidth
= (float)ptm
->tmMaxCharWidth
* scale_x
;
4288 /*************************************************************
4289 * WineEngGetTextMetrics
4292 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4294 EnterCriticalSection( &freetype_cs
);
4296 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4297 if(!get_bitmap_text_metrics(font
))
4299 LeaveCriticalSection( &freetype_cs
);
4305 LeaveCriticalSection( &freetype_cs
);
4308 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
4309 scale_font_metrics(font
, ptm
);
4310 LeaveCriticalSection( &freetype_cs
);
4315 /*************************************************************
4316 * WineEngGetOutlineTextMetrics
4319 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4320 OUTLINETEXTMETRICW
*potm
)
4322 FT_Face ft_face
= font
->ft_face
;
4323 UINT needed
, lenfam
, lensty
, ret
;
4325 TT_HoriHeader
*pHori
;
4326 TT_Postscript
*pPost
;
4327 FT_Fixed x_scale
, y_scale
;
4328 WCHAR
*family_nameW
, *style_nameW
;
4329 static const WCHAR spaceW
[] = {' ', '\0'};
4331 INT ascent
, descent
;
4333 TRACE("font=%p\n", font
);
4335 if(!FT_IS_SCALABLE(ft_face
))
4338 EnterCriticalSection( &freetype_cs
);
4341 if(cbSize
>= font
->potm
->otmSize
)
4343 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4344 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4346 LeaveCriticalSection( &freetype_cs
);
4347 return font
->potm
->otmSize
;
4351 needed
= sizeof(*potm
);
4353 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
4354 family_nameW
= strdupW(font
->name
);
4356 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
4358 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
4359 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
4360 style_nameW
, lensty
/sizeof(WCHAR
));
4362 /* These names should be read from the TT name table */
4364 /* length of otmpFamilyName */
4367 /* length of otmpFaceName */
4368 if(!strcasecmp(ft_face
->style_name
, "regular")) {
4369 needed
+= lenfam
; /* just the family name */
4371 needed
+= lenfam
+ lensty
; /* family + " " + style */
4374 /* length of otmpStyleName */
4377 /* length of otmpFullName */
4378 needed
+= lenfam
+ lensty
;
4381 x_scale
= ft_face
->size
->metrics
.x_scale
;
4382 y_scale
= ft_face
->size
->metrics
.y_scale
;
4384 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4386 FIXME("Can't find OS/2 table - not TT font?\n");
4391 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4393 FIXME("Can't find HHEA table - not TT font?\n");
4398 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
4400 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",
4401 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
4402 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
4403 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
4404 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
4405 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
4407 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
4408 font
->potm
->otmSize
= needed
;
4410 #define TM font->potm->otmTextMetrics
4412 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
4413 ascent
= pHori
->Ascender
;
4414 descent
= -pHori
->Descender
;
4416 ascent
= pOS2
->usWinAscent
;
4417 descent
= pOS2
->usWinDescent
;
4421 TM
.tmAscent
= font
->yMax
;
4422 TM
.tmDescent
= -font
->yMin
;
4423 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4425 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4426 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4427 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4428 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4431 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4434 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4436 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4437 ((ascent
+ descent
) -
4438 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4440 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4441 if (TM
.tmAveCharWidth
== 0) {
4442 TM
.tmAveCharWidth
= 1;
4444 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4445 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4447 TM
.tmDigitizedAspectX
= 300;
4448 TM
.tmDigitizedAspectY
= 300;
4449 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4450 * symbol range to 0 - f0ff
4452 if (font
->charset
== SYMBOL_CHARSET
)
4455 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4456 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4457 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4458 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4459 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4460 TM
.tmUnderlined
= font
->underline
;
4461 TM
.tmStruckOut
= font
->strikeout
;
4463 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4464 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4465 (pOS2
->version
== 0xFFFFU
||
4466 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4467 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4469 TM
.tmPitchAndFamily
= 0;
4471 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4472 case PAN_FAMILY_SCRIPT
:
4473 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4475 case PAN_FAMILY_DECORATIVE
:
4476 case PAN_FAMILY_PICTORIAL
:
4477 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4479 case PAN_FAMILY_TEXT_DISPLAY
:
4480 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4481 TM
.tmPitchAndFamily
= FF_MODERN
;
4483 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4484 case PAN_SERIF_NORMAL_SANS
:
4485 case PAN_SERIF_OBTUSE_SANS
:
4486 case PAN_SERIF_PERP_SANS
:
4487 TM
.tmPitchAndFamily
|= FF_SWISS
;
4490 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4495 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4498 if(FT_IS_SCALABLE(ft_face
))
4499 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4501 if(FT_IS_SFNT(ft_face
))
4503 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
4504 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
4506 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4509 TM
.tmCharSet
= font
->charset
;
4512 font
->potm
->otmFiller
= 0;
4513 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4514 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4515 font
->potm
->otmfsType
= pOS2
->fsType
;
4516 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4517 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4518 font
->potm
->otmItalicAngle
= 0; /* POST table */
4519 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4520 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4521 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4522 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4523 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4524 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
4525 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4526 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
4527 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
4528 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
4529 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
4530 font
->potm
->otmMacDescent
= 0;
4531 font
->potm
->otmMacLineGap
= 0;
4532 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
4533 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
4534 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
4535 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
4536 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
4537 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
4538 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
4539 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
4540 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
4541 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
4542 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
4544 font
->potm
->otmsUnderscoreSize
= 0;
4545 font
->potm
->otmsUnderscorePosition
= 0;
4547 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
4548 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
4551 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4552 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
4553 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
4554 strcpyW((WCHAR
*)cp
, family_nameW
);
4556 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
4557 strcpyW((WCHAR
*)cp
, style_nameW
);
4559 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
4560 strcpyW((WCHAR
*)cp
, family_nameW
);
4561 if(strcasecmp(ft_face
->style_name
, "regular")) {
4562 strcatW((WCHAR
*)cp
, spaceW
);
4563 strcatW((WCHAR
*)cp
, style_nameW
);
4564 cp
+= lenfam
+ lensty
;
4567 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
4568 strcpyW((WCHAR
*)cp
, family_nameW
);
4569 strcatW((WCHAR
*)cp
, spaceW
);
4570 strcatW((WCHAR
*)cp
, style_nameW
);
4573 if(potm
&& needed
<= cbSize
)
4575 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4576 scale_font_metrics(font
, &potm
->otmTextMetrics
);
4580 HeapFree(GetProcessHeap(), 0, style_nameW
);
4581 HeapFree(GetProcessHeap(), 0, family_nameW
);
4583 LeaveCriticalSection( &freetype_cs
);
4587 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
4589 HFONTLIST
*hfontlist
;
4590 child
->font
= alloc_font();
4591 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
4592 if(!child
->font
->ft_face
)
4594 free_font(child
->font
);
4599 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
4600 child
->font
->orientation
= font
->orientation
;
4601 child
->font
->scale_y
= font
->scale_y
;
4602 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
4603 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
4604 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
4605 child
->font
->base_font
= font
;
4606 list_add_head(&child_font_list
, &child
->font
->entry
);
4607 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
4611 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
4614 CHILD_FONT
*child_font
;
4617 font
= font
->base_font
;
4619 *linked_font
= font
;
4621 if((*glyph
= get_glyph_index(font
, c
)))
4624 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
4626 if(!child_font
->font
)
4627 if(!load_child_font(font
, child_font
))
4630 if(!child_font
->font
->ft_face
)
4632 g
= get_glyph_index(child_font
->font
, c
);
4636 *linked_font
= child_font
->font
;
4643 /*************************************************************
4644 * WineEngGetCharWidth
4647 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4652 FT_UInt glyph_index
;
4653 GdiFont
*linked_font
;
4655 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4657 EnterCriticalSection( &freetype_cs
);
4658 for(c
= firstChar
; c
<= lastChar
; c
++) {
4659 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4660 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4661 &gm
, 0, NULL
, NULL
);
4662 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
4664 LeaveCriticalSection( &freetype_cs
);
4668 /*************************************************************
4669 * WineEngGetCharABCWidths
4672 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4677 FT_UInt glyph_index
;
4678 GdiFont
*linked_font
;
4680 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4682 if(!FT_IS_SCALABLE(font
->ft_face
))
4685 EnterCriticalSection( &freetype_cs
);
4687 for(c
= firstChar
; c
<= lastChar
; c
++) {
4688 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4689 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4690 &gm
, 0, NULL
, NULL
);
4691 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
4692 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
4693 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
4694 FONT_GM(linked_font
,glyph_index
)->bbx
;
4696 LeaveCriticalSection( &freetype_cs
);
4700 /*************************************************************
4701 * WineEngGetCharABCWidthsI
4704 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4709 FT_UInt glyph_index
;
4710 GdiFont
*linked_font
;
4712 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
4715 EnterCriticalSection( &freetype_cs
);
4717 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
4719 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
4720 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4721 &gm
, 0, NULL
, NULL
);
4722 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
4723 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
4724 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
4725 - FONT_GM(linked_font
,c
)->bbx
;
4728 for(c
= 0; c
< count
; c
++) {
4729 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4730 &gm
, 0, NULL
, NULL
);
4731 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
4732 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
4733 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
4734 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
4737 LeaveCriticalSection( &freetype_cs
);
4741 /*************************************************************
4742 * WineEngGetTextExtentExPoint
4745 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4746 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4752 FT_UInt glyph_index
;
4753 GdiFont
*linked_font
;
4755 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
4758 EnterCriticalSection( &freetype_cs
);
4761 WineEngGetTextMetrics(font
, &tm
);
4762 size
->cy
= tm
.tmHeight
;
4764 for(idx
= 0; idx
< count
; idx
++) {
4765 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
4766 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4767 &gm
, 0, NULL
, NULL
);
4768 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
4770 if (! pnfit
|| ext
<= max_ext
) {
4780 LeaveCriticalSection( &freetype_cs
);
4781 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4785 /*************************************************************
4786 * WineEngGetTextExtentExPointI
4789 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4790 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4797 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
4799 EnterCriticalSection( &freetype_cs
);
4802 WineEngGetTextMetrics(font
, &tm
);
4803 size
->cy
= tm
.tmHeight
;
4805 for(idx
= 0; idx
< count
; idx
++) {
4806 WineEngGetGlyphOutline(font
, indices
[idx
],
4807 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
4809 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
4811 if (! pnfit
|| ext
<= max_ext
) {
4821 LeaveCriticalSection( &freetype_cs
);
4822 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4826 /*************************************************************
4827 * WineEngGetFontData
4830 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4833 FT_Face ft_face
= font
->ft_face
;
4837 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4838 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
4839 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
4841 if(!FT_IS_SFNT(ft_face
))
4849 if(table
) { /* MS tags differ in endidness from FT ones */
4850 table
= table
>> 24 | table
<< 24 |
4851 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
4854 /* make sure value of len is the value freetype says it needs */
4857 FT_ULong needed
= 0;
4858 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
4859 if( !err
&& needed
< len
) len
= needed
;
4861 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
4864 TRACE("Can't find table %c%c%c%c\n",
4865 /* bytes were reversed */
4866 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4867 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4873 /*************************************************************
4874 * WineEngGetTextFace
4877 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4880 lstrcpynW(str
, font
->name
, count
);
4881 return strlenW(font
->name
);
4883 return strlenW(font
->name
) + 1;
4886 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4888 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
4889 return font
->charset
;
4892 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4894 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
4895 struct list
*first_hfont
;
4898 EnterCriticalSection( &freetype_cs
);
4899 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
4900 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
4901 if(font
== linked_font
)
4902 *new_hfont
= dc
->hFont
;
4905 first_hfont
= list_head(&linked_font
->hfontlist
);
4906 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
4908 LeaveCriticalSection( &freetype_cs
);
4912 /* Retrieve a list of supported Unicode ranges for a given font.
4913 * Can be called with NULL gs to calculate the buffer size. Returns
4914 * the number of ranges found.
4916 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
4918 DWORD num_ranges
= 0;
4920 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4923 FT_ULong char_code
, char_code_prev
;
4926 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
4928 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4929 face
->num_glyphs
, glyph_code
, char_code
);
4931 if (!glyph_code
) return 0;
4935 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4936 gs
->ranges
[0].cGlyphs
= 0;
4937 gs
->cGlyphsSupported
= 0;
4943 if (char_code
< char_code_prev
)
4945 ERR("expected increasing char code from FT_Get_Next_Char\n");
4948 if (char_code
- char_code_prev
> 1)
4953 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4954 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4955 gs
->cGlyphsSupported
++;
4960 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4961 gs
->cGlyphsSupported
++;
4963 char_code_prev
= char_code
;
4964 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
4968 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
4973 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
4976 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
4978 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
4981 glyphset
->cbThis
= size
;
4982 glyphset
->cRanges
= num_ranges
;
4987 /*************************************************************
4990 BOOL
WineEngFontIsLinked(GdiFont
*font
)
4993 EnterCriticalSection( &freetype_cs
);
4994 ret
= !list_empty(&font
->child_fonts
);
4995 LeaveCriticalSection( &freetype_cs
);
4999 static BOOL
is_hinting_enabled(void)
5001 /* Use the >= 2.2.0 function if available */
5002 if(pFT_Get_TrueType_Engine_Type
)
5004 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
5005 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
5007 #ifdef FT_DRIVER_HAS_HINTER
5012 /* otherwise if we've been compiled with < 2.2.0 headers
5013 use the internal macro */
5014 mod
= pFT_Get_Module(library
, "truetype");
5015 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
5023 /*************************************************************************
5024 * GetRasterizerCaps (GDI32.@)
5026 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5028 static int hinting
= -1;
5032 hinting
= is_hinting_enabled();
5033 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
5036 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5037 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
5038 lprs
->nLanguageID
= 0;
5042 /*************************************************************************
5043 * Kerning support for TrueType fonts
5045 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5047 struct TT_kern_table
5053 struct TT_kern_subtable
5062 USHORT horizontal
: 1;
5064 USHORT cross_stream
: 1;
5065 USHORT override
: 1;
5066 USHORT reserved1
: 4;
5072 struct TT_format0_kern_subtable
5076 USHORT entrySelector
;
5087 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
5088 const struct TT_format0_kern_subtable
*tt_f0_ks
,
5089 const USHORT
*glyph_to_char
,
5090 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
5093 const struct TT_kern_pair
*tt_kern_pair
;
5095 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
5097 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
5099 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5100 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
5101 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
5103 if (!kern_pair
|| !cPairs
)
5106 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
5108 nPairs
= min(nPairs
, cPairs
);
5110 for (i
= 0; i
< nPairs
; i
++)
5112 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
5113 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
5114 /* this algorithm appears to better match what Windows does */
5115 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
5116 if (kern_pair
->iKernAmount
< 0)
5118 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
5119 kern_pair
->iKernAmount
-= font
->ppem
;
5121 else if (kern_pair
->iKernAmount
> 0)
5123 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
5124 kern_pair
->iKernAmount
+= font
->ppem
;
5126 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
5128 TRACE("left %u right %u value %d\n",
5129 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
5133 TRACE("copied %u entries\n", nPairs
);
5137 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5141 const struct TT_kern_table
*tt_kern_table
;
5142 const struct TT_kern_subtable
*tt_kern_subtable
;
5144 USHORT
*glyph_to_char
;
5146 EnterCriticalSection( &freetype_cs
);
5147 if (font
->total_kern_pairs
!= (DWORD
)-1)
5149 if (cPairs
&& kern_pair
)
5151 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5152 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5153 LeaveCriticalSection( &freetype_cs
);
5156 LeaveCriticalSection( &freetype_cs
);
5157 return font
->total_kern_pairs
;
5160 font
->total_kern_pairs
= 0;
5162 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
5164 if (length
== GDI_ERROR
)
5166 TRACE("no kerning data in the font\n");
5167 LeaveCriticalSection( &freetype_cs
);
5171 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
5174 WARN("Out of memory\n");
5175 LeaveCriticalSection( &freetype_cs
);
5179 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
5181 /* build a glyph index to char code map */
5182 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
5185 WARN("Out of memory allocating a glyph index to char code map\n");
5186 HeapFree(GetProcessHeap(), 0, buf
);
5187 LeaveCriticalSection( &freetype_cs
);
5191 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5197 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
5199 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5200 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
5204 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5206 /* FIXME: This doesn't match what Windows does: it does some fancy
5207 * things with duplicate glyph index to char code mappings, while
5208 * we just avoid overriding existing entries.
5210 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
5211 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
5213 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
5220 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
5221 for (n
= 0; n
<= 65535; n
++)
5222 glyph_to_char
[n
] = (USHORT
)n
;
5225 tt_kern_table
= buf
;
5226 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
5227 TRACE("version %u, nTables %u\n",
5228 GET_BE_WORD(tt_kern_table
->version
), nTables
);
5230 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
5232 for (i
= 0; i
< nTables
; i
++)
5234 struct TT_kern_subtable tt_kern_subtable_copy
;
5236 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
5237 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
5238 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
5240 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5241 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
5242 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
5244 /* According to the TrueType specification this is the only format
5245 * that will be properly interpreted by Windows and OS/2
5247 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
5249 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
5251 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5252 glyph_to_char
, NULL
, 0);
5253 font
->total_kern_pairs
+= new_chunk
;
5255 if (!font
->kern_pairs
)
5256 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
5257 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5259 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
5260 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
5262 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
5263 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
5266 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
5268 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
5271 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
5272 HeapFree(GetProcessHeap(), 0, buf
);
5274 if (cPairs
&& kern_pair
)
5276 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5277 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5278 LeaveCriticalSection( &freetype_cs
);
5281 LeaveCriticalSection( &freetype_cs
);
5282 return font
->total_kern_pairs
;
5285 #else /* HAVE_FREETYPE */
5287 /*************************************************************************/
5289 BOOL
WineEngInit(void)
5293 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
5297 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
5302 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5307 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
5308 LPWORD pgi
, DWORD flags
)
5313 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
5314 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5317 ERR("called but we don't have FreeType\n");
5321 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5323 ERR("called but we don't have FreeType\n");
5327 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5328 OUTLINETEXTMETRICW
*potm
)
5330 ERR("called but we don't have FreeType\n");
5334 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5337 ERR("called but we don't have FreeType\n");
5341 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5344 ERR("called but we don't have FreeType\n");
5348 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5351 ERR("called but we don't have FreeType\n");
5355 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5356 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5358 ERR("called but we don't have FreeType\n");
5362 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5363 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
5365 ERR("called but we don't have FreeType\n");
5369 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5372 ERR("called but we don't have FreeType\n");
5376 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5378 ERR("called but we don't have FreeType\n");
5382 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5388 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
5394 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
5400 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5403 return DEFAULT_CHARSET
;
5406 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5411 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5413 FIXME("(%p, %p): stub\n", font
, glyphset
);
5417 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5422 /*************************************************************************
5423 * GetRasterizerCaps (GDI32.@)
5425 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5427 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5429 lprs
->nLanguageID
= 0;
5433 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5435 ERR("called but we don't have FreeType\n");
5439 #endif /* HAVE_FREETYPE */