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>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(font
);
96 #ifdef HAVE_FT2BUILD_H
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
120 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
121 #include <freetype/internal/sfnt.h>
123 #ifdef HAVE_FREETYPE_FTTRIGON_H
124 #include <freetype/fttrigon.h>
126 #ifdef HAVE_FREETYPE_FTWINFNT_H
127 #include <freetype/ftwinfnt.h>
129 #ifdef HAVE_FREETYPE_FTMODAPI_H
130 #include <freetype/ftmodapi.h>
132 #ifdef HAVE_FREETYPE_FTLCDFIL_H
133 #include <freetype/ftlcdfil.h>
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
139 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType
;
145 static FT_Library library
= 0;
152 static FT_Version_t FT_Version
;
153 static DWORD FT_SimpleVersion
;
155 static void *ft_handle
= NULL
;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Vector_Unit
);
159 MAKE_FUNCPTR(FT_Done_Face
);
160 MAKE_FUNCPTR(FT_Get_Char_Index
);
161 MAKE_FUNCPTR(FT_Get_Module
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
165 MAKE_FUNCPTR(FT_Init_FreeType
);
166 MAKE_FUNCPTR(FT_Load_Glyph
);
167 MAKE_FUNCPTR(FT_Matrix_Multiply
);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
171 MAKE_FUNCPTR(FT_MulFix
);
173 MAKE_FUNCPTR(FT_New_Face
);
174 MAKE_FUNCPTR(FT_New_Memory_Face
);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
176 MAKE_FUNCPTR(FT_Outline_Transform
);
177 MAKE_FUNCPTR(FT_Outline_Translate
);
178 MAKE_FUNCPTR(FT_Select_Charmap
);
179 MAKE_FUNCPTR(FT_Set_Charmap
);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
181 MAKE_FUNCPTR(FT_Vector_Transform
);
182 MAKE_FUNCPTR(FT_Render_Glyph
);
183 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
184 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
185 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
186 static FT_ULong (*pFT_Get_Next_Char
)(FT_Face
,FT_ULong
,FT_UInt
*);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
191 #ifdef HAVE_FREETYPE_FTWINFNT_H
192 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
195 #ifdef SONAME_LIBFONTCONFIG
196 #include <fontconfig/fontconfig.h>
197 MAKE_FUNCPTR(FcConfigGetCurrent
);
198 MAKE_FUNCPTR(FcFontList
);
199 MAKE_FUNCPTR(FcFontSetDestroy
);
200 MAKE_FUNCPTR(FcInit
);
201 MAKE_FUNCPTR(FcObjectSetAdd
);
202 MAKE_FUNCPTR(FcObjectSetCreate
);
203 MAKE_FUNCPTR(FcObjectSetDestroy
);
204 MAKE_FUNCPTR(FcPatternCreate
);
205 MAKE_FUNCPTR(FcPatternDestroy
);
206 MAKE_FUNCPTR(FcPatternGetBool
);
207 MAKE_FUNCPTR(FcPatternGetString
);
213 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
214 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
215 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
218 #ifndef ft_encoding_none
219 #define FT_ENCODING_NONE ft_encoding_none
221 #ifndef ft_encoding_ms_symbol
222 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
224 #ifndef ft_encoding_unicode
225 #define FT_ENCODING_UNICODE ft_encoding_unicode
227 #ifndef ft_encoding_apple_roman
228 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
231 #ifdef WORDS_BIGENDIAN
232 #define GET_BE_WORD(x) (x)
234 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
237 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
244 FT_Short internal_leading
;
247 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
248 So to let this compile on older versions of FreeType we'll define the
249 new structure here. */
251 FT_Short height
, width
;
252 FT_Pos size
, x_ppem
, y_ppem
;
258 NEWTEXTMETRICEXW ntm
;
262 typedef struct tagFace
{
267 DWORD font_data_size
;
270 FONTSIGNATURE fs_links
;
272 FT_Fixed font_version
;
274 Bitmap_Size size
; /* set if face is a bitmap */
275 BOOL external
; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily
*family
;
277 /* Cached data for Enum */
278 struct enum_data
*cached_enum_data
;
281 typedef struct tagFamily
{
283 const WCHAR
*FamilyName
;
289 INT adv
; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST
{
322 struct list hfontlist
;
323 OUTLINETEXTMETRICW
*potm
;
324 DWORD total_kern_pairs
;
325 KERNINGPAIR
*kern_pairs
;
326 struct list child_fonts
;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping
*mapping
;
353 const WCHAR
*font_name
;
357 struct enum_charset_element
{
363 struct enum_charset_list
{
365 struct enum_charset_element element
[32];
368 #define GM_BLOCK_SIZE 128
369 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
371 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
372 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
373 #define UNUSED_CACHE_SIZE 10
374 static struct list child_font_list
= LIST_INIT(child_font_list
);
375 static struct list system_links
= LIST_INIT(system_links
);
377 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
379 static struct list font_list
= LIST_INIT(font_list
);
381 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
382 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
383 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
385 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
386 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
387 'W','i','n','d','o','w','s','\\',
388 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
389 'F','o','n','t','s','\0'};
391 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
392 'W','i','n','d','o','w','s',' ','N','T','\\',
393 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
394 'F','o','n','t','s','\0'};
396 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
397 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
398 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
399 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
401 static const WCHAR
* const SystemFontValues
[4] = {
408 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
409 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
411 /* Interesting and well-known (frequently-assumed!) font names */
412 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
413 static const WCHAR Microsoft_Sans_Serif
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
414 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
415 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
416 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
417 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
418 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
419 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
421 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
422 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
423 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
424 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
425 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
426 'E','u','r','o','p','e','a','n','\0'};
427 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
428 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
429 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
430 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
431 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
432 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
433 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
434 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
435 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
436 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
437 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
438 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
440 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
450 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
458 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
467 typedef struct tagFontSubst
{
483 static struct list mappings_list
= LIST_INIT( mappings_list
);
485 static CRITICAL_SECTION freetype_cs
;
486 static CRITICAL_SECTION_DEBUG critsect_debug
=
489 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
490 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
492 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
494 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
496 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
497 static BOOL use_default_fallback
= FALSE
;
499 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
501 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
502 'W','i','n','d','o','w','s',' ','N','T','\\',
503 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
504 'S','y','s','t','e','m','L','i','n','k',0};
506 /****************************************
507 * Notes on .fon files
509 * The fonts System, FixedSys and Terminal are special. There are typically multiple
510 * versions installed for different resolutions and codepages. Windows stores which one to use
511 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
513 * FIXEDFON.FON FixedSys
515 * OEMFONT.FON Terminal
516 * LogPixels Current dpi set by the display control panel applet
517 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
518 * also has a LogPixels value that appears to mirror this)
520 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
521 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
522 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
523 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
524 * so that makes sense.
526 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
527 * to be mapped into the registry on Windows 2000 at least).
530 * ega80woa.fon=ega80850.fon
531 * ega40woa.fon=ega40850.fon
532 * cga80woa.fon=cga80850.fon
533 * cga40woa.fon=cga40850.fon
536 /* These are all structures needed for the GSUB table */
538 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
539 #define TATEGAKI_LOWER_BOUND 0x02F1
555 GSUB_ScriptRecord ScriptRecord
[1];
561 } GSUB_LangSysRecord
;
566 GSUB_LangSysRecord LangSysRecord
[1];
570 WORD LookupOrder
; /* Reserved */
571 WORD ReqFeatureIndex
;
573 WORD FeatureIndex
[1];
579 } GSUB_FeatureRecord
;
583 GSUB_FeatureRecord FeatureRecord
[1];
587 WORD FeatureParams
; /* Reserved */
589 WORD LookupListIndex
[1];
608 } GSUB_CoverageFormat1
;
613 WORD StartCoverageIndex
;
619 GSUB_RangeRecord RangeRecord
[1];
620 } GSUB_CoverageFormat2
;
623 WORD SubstFormat
; /* = 1 */
626 } GSUB_SingleSubstFormat1
;
629 WORD SubstFormat
; /* = 2 */
633 }GSUB_SingleSubstFormat2
;
635 #ifdef HAVE_CARBON_CARBON_H
636 static char *find_cache_dir(void)
640 static char cached_path
[MAX_PATH
];
641 static const char *wine
= "/Wine", *fonts
= "/Fonts";
643 if(*cached_path
) return cached_path
;
645 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
648 WARN("can't create cached data folder\n");
651 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
654 WARN("can't create cached data path\n");
658 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
660 ERR("Could not create full path\n");
664 strcat(cached_path
, wine
);
666 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
668 WARN("Couldn't mkdir %s\n", cached_path
);
672 strcat(cached_path
, fonts
);
673 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
675 WARN("Couldn't mkdir %s\n", cached_path
);
682 /******************************************************************
685 * Extracts individual TrueType font files from a Mac suitcase font
686 * and saves them into the user's caches directory (see
688 * Returns a NULL terminated array of filenames.
690 * We do this because they are apps that try to read ttf files
691 * themselves and they don't like Mac suitcase files.
693 static char **expand_mac_font(const char *path
)
700 const char *filename
;
704 unsigned int size
, max_size
;
707 TRACE("path %s\n", path
);
709 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
712 WARN("failed to get ref\n");
716 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
719 TRACE("no data fork, so trying resource fork\n");
720 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
723 TRACE("unable to open resource fork\n");
730 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
733 CloseResFile(res_ref
);
737 out_dir
= find_cache_dir();
739 filename
= strrchr(path
, '/');
740 if(!filename
) filename
= path
;
743 /* output filename has the form out_dir/filename_%04x.ttf */
744 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
751 unsigned short *num_faces_ptr
, num_faces
, face
;
754 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
756 fond
= Get1IndResource(fond_res
, idx
);
758 TRACE("got fond resource %d\n", idx
);
761 fam_rec
= *(FamRec
**)fond
;
762 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
763 num_faces
= GET_BE_WORD(*num_faces_ptr
);
765 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
766 TRACE("num faces %04x\n", num_faces
);
767 for(face
= 0; face
< num_faces
; face
++, assoc
++)
770 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
771 unsigned short size
, font_id
;
774 size
= GET_BE_WORD(assoc
->fontSize
);
775 font_id
= GET_BE_WORD(assoc
->fontID
);
778 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
782 TRACE("trying to load sfnt id %04x\n", font_id
);
783 sfnt
= GetResource(sfnt_res
, font_id
);
786 TRACE("can't get sfnt resource %04x\n", font_id
);
790 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
795 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
797 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
798 if(fd
!= -1 || errno
== EEXIST
)
802 unsigned char *sfnt_data
;
805 sfnt_data
= *(unsigned char**)sfnt
;
806 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
810 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
813 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
815 ret
.array
[ret
.size
++] = output
;
819 WARN("unable to create %s\n", output
);
820 HeapFree(GetProcessHeap(), 0, output
);
823 ReleaseResource(sfnt
);
826 ReleaseResource(fond
);
829 CloseResFile(res_ref
);
834 #endif /* HAVE_CARBON_CARBON_H */
836 static inline BOOL
is_win9x(void)
838 return GetVersion() & 0x80000000;
841 This function builds an FT_Fixed from a double. It fails if the absolute
842 value of the float number is greater than 32768.
844 static inline FT_Fixed
FT_FixedFromFloat(double f
)
850 This function builds an FT_Fixed from a FIXED. It simply put f.value
851 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
853 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
855 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
859 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
864 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
865 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
867 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
868 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
870 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
872 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
874 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
878 file
= strrchr(face
->file
, '/');
883 if(!strcasecmp(file
, file_nameA
))
885 HeapFree(GetProcessHeap(), 0, file_nameA
);
890 HeapFree(GetProcessHeap(), 0, file_nameA
);
894 static Family
*find_family_from_name(const WCHAR
*name
)
898 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
900 if(!strcmpiW(family
->FamilyName
, name
))
907 static void DumpSubstList(void)
911 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
913 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
914 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
915 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
917 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
918 debugstr_w(psub
->to
.name
));
923 static LPWSTR
strdupW(LPCWSTR p
)
926 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
927 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
932 static LPSTR
strdupA(LPCSTR p
)
935 DWORD len
= (strlen(p
) + 1);
936 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
941 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
946 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
948 if(!strcmpiW(element
->from
.name
, from_name
) &&
949 (element
->from
.charset
== from_charset
||
950 element
->from
.charset
== -1))
957 #define ADD_FONT_SUBST_FORCE 1
959 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
961 FontSubst
*from_exist
, *to_exist
;
963 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
965 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
967 list_remove(&from_exist
->entry
);
968 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
969 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
970 HeapFree(GetProcessHeap(), 0, from_exist
);
976 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
980 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
981 subst
->to
.name
= strdupW(to_exist
->to
.name
);
984 list_add_tail(subst_list
, &subst
->entry
);
989 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
990 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
991 HeapFree(GetProcessHeap(), 0, subst
);
995 static void split_subst_info(NameCs
*nc
, LPSTR str
)
997 CHAR
*p
= strrchr(str
, ',');
1002 nc
->charset
= strtol(p
+1, NULL
, 10);
1005 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
1006 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1007 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
1010 static void LoadSubstList(void)
1014 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1018 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1019 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1020 &hkey
) == ERROR_SUCCESS
) {
1022 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1023 &valuelen
, &datalen
, NULL
, NULL
);
1025 valuelen
++; /* returned value doesn't include room for '\0' */
1026 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1027 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1031 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1032 &dlen
) == ERROR_SUCCESS
) {
1033 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1035 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1036 split_subst_info(&psub
->from
, value
);
1037 split_subst_info(&psub
->to
, data
);
1039 /* Win 2000 doesn't allow mapping between different charsets
1040 or mapping of DEFAULT_CHARSET */
1041 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1042 psub
->to
.charset
== DEFAULT_CHARSET
) {
1043 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1044 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1045 HeapFree(GetProcessHeap(), 0, psub
);
1047 add_font_subst(&font_subst_list
, psub
, 0);
1049 /* reset dlen and vlen */
1053 HeapFree(GetProcessHeap(), 0, data
);
1054 HeapFree(GetProcessHeap(), 0, value
);
1060 /*****************************************************************
1061 * get_name_table_entry
1063 * Supply the platform, encoding, language and name ids in req
1064 * and if the name exists the function will fill in the string
1065 * and string_len members. The string is owned by FreeType so
1066 * don't free it. Returns TRUE if the name is found else FALSE.
1068 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1071 FT_UInt num_names
, name_index
;
1073 if(FT_IS_SFNT(ft_face
))
1075 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1077 for(name_index
= 0; name_index
< num_names
; name_index
++)
1079 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1081 if((name
.platform_id
== req
->platform_id
) &&
1082 (name
.encoding_id
== req
->encoding_id
) &&
1083 (name
.language_id
== req
->language_id
) &&
1084 (name
.name_id
== req
->name_id
))
1086 req
->string
= name
.string
;
1087 req
->string_len
= name
.string_len
;
1094 req
->string_len
= 0;
1098 static WCHAR
*get_familyname(FT_Face ft_face
)
1100 WCHAR
*family
= NULL
;
1103 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1104 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1105 name
.language_id
= GetUserDefaultLCID();
1106 name
.name_id
= TT_NAME_ID_FONT_FAMILY
;
1108 if(get_name_table_entry(ft_face
, &name
))
1112 /* String is not nul terminated and string_len is a byte length. */
1113 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1114 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1116 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1117 family
[i
] = GET_BE_WORD(*tmp
);
1120 TRACE("Got localised name %s\n", debugstr_w(family
));
1127 /*****************************************************************
1130 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1131 * of FreeType that don't export this function.
1134 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1139 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1140 if(pFT_Load_Sfnt_Table
)
1142 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1144 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1145 else /* Do it the hard way */
1147 TT_Face tt_face
= (TT_Face
) ft_face
;
1148 SFNT_Interface
*sfnt
;
1149 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1152 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1156 /* A field was added in the middle of the structure in 2.1.x */
1157 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1159 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1167 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1168 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1169 "Please upgrade your freetype library.\n");
1172 err
= FT_Err_Unimplemented_Feature
;
1178 static inline int TestStyles(DWORD flags
, DWORD styles
)
1180 return (flags
& styles
) == styles
;
1183 static int StyleOrdering(Face
*face
)
1185 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1187 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1189 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1191 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1194 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1195 debugstr_w(face
->family
->FamilyName
),
1196 debugstr_w(face
->StyleName
),
1202 /* Add a style of face to a font family using an ordering of the list such
1203 that regular fonts come before bold and italic, and single styles come
1204 before compound styles. */
1205 static void AddFaceToFamily(Face
*face
, Family
*family
)
1209 LIST_FOR_EACH( entry
, &family
->faces
)
1211 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1212 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1214 list_add_before( entry
, &face
->entry
);
1217 #define ADDFONT_EXTERNAL_FONT 0x01
1218 #define ADDFONT_FORCE_BITMAP 0x02
1219 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1223 TT_Header
*pHeader
= NULL
;
1224 WCHAR
*english_family
, *localised_family
, *StyleW
;
1228 struct list
*family_elem_ptr
, *face_elem_ptr
;
1230 FT_Long face_index
= 0, num_faces
;
1231 #ifdef HAVE_FREETYPE_FTWINFNT_H
1232 FT_WinFNT_HeaderRec winfnt_header
;
1234 int i
, bitmap_num
, internal_leading
;
1237 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1238 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1240 #ifdef HAVE_CARBON_CARBON_H
1241 if(file
&& !fake_family
)
1243 char **mac_list
= expand_mac_font(file
);
1246 BOOL had_one
= FALSE
;
1248 for(cursor
= mac_list
; *cursor
; cursor
++)
1251 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1252 HeapFree(GetProcessHeap(), 0, *cursor
);
1254 HeapFree(GetProcessHeap(), 0, mac_list
);
1259 #endif /* HAVE_CARBON_CARBON_H */
1262 char *family_name
= fake_family
;
1266 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1267 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1270 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1271 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1275 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1279 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*/
1280 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1281 pFT_Done_Face(ft_face
);
1285 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1286 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1287 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1288 pFT_Done_Face(ft_face
);
1292 if(FT_IS_SFNT(ft_face
))
1294 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1295 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1296 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1298 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1299 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1300 pFT_Done_Face(ft_face
);
1304 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1305 we don't want to load these. */
1306 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1310 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1312 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1313 pFT_Done_Face(ft_face
);
1319 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1320 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1321 pFT_Done_Face(ft_face
);
1325 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1327 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1328 pFT_Done_Face(ft_face
);
1334 localised_family
= get_familyname(ft_face
);
1335 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1337 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1338 HeapFree(GetProcessHeap(), 0, localised_family
);
1339 num_faces
= ft_face
->num_faces
;
1340 pFT_Done_Face(ft_face
);
1343 HeapFree(GetProcessHeap(), 0, localised_family
);
1347 family_name
= ft_face
->family_name
;
1351 My_FT_Bitmap_Size
*size
= NULL
;
1354 if(!FT_IS_SCALABLE(ft_face
))
1355 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1357 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1358 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1359 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1361 localised_family
= NULL
;
1363 localised_family
= get_familyname(ft_face
);
1364 if(localised_family
&& !strcmpiW(localised_family
, english_family
)) {
1365 HeapFree(GetProcessHeap(), 0, localised_family
);
1366 localised_family
= NULL
;
1371 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1372 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1373 if(!strcmpiW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1378 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1379 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1380 list_init(&family
->faces
);
1381 list_add_tail(&font_list
, &family
->entry
);
1383 if(localised_family
) {
1384 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1385 subst
->from
.name
= strdupW(english_family
);
1386 subst
->from
.charset
= -1;
1387 subst
->to
.name
= strdupW(localised_family
);
1388 subst
->to
.charset
= -1;
1389 add_font_subst(&font_subst_list
, subst
, 0);
1392 HeapFree(GetProcessHeap(), 0, localised_family
);
1393 HeapFree(GetProcessHeap(), 0, english_family
);
1395 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1396 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1397 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1399 internal_leading
= 0;
1400 memset(&fs
, 0, sizeof(fs
));
1402 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1404 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1405 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1406 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1407 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1408 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1409 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1410 if(pOS2
->version
== 0) {
1413 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1414 fs
.fsCsb
[0] |= FS_LATIN1
;
1416 fs
.fsCsb
[0] |= FS_SYMBOL
;
1419 #ifdef HAVE_FREETYPE_FTWINFNT_H
1420 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1422 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1423 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1424 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1426 internal_leading
= winfnt_header
.internal_leading
;
1430 face_elem_ptr
= list_head(&family
->faces
);
1431 while(face_elem_ptr
) {
1432 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1433 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1434 if(!strcmpiW(face
->StyleName
, StyleW
) &&
1435 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1436 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1437 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1438 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1441 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1442 HeapFree(GetProcessHeap(), 0, StyleW
);
1443 pFT_Done_Face(ft_face
);
1446 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1447 TRACE("Original font is newer so skipping this one\n");
1448 HeapFree(GetProcessHeap(), 0, StyleW
);
1449 pFT_Done_Face(ft_face
);
1452 TRACE("Replacing original with this one\n");
1453 list_remove(&face
->entry
);
1454 HeapFree(GetProcessHeap(), 0, face
->file
);
1455 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1456 HeapFree(GetProcessHeap(), 0, face
);
1461 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1462 face
->cached_enum_data
= NULL
;
1463 face
->StyleName
= StyleW
;
1466 face
->file
= strdupA(file
);
1467 face
->font_data_ptr
= NULL
;
1468 face
->font_data_size
= 0;
1473 face
->font_data_ptr
= font_data_ptr
;
1474 face
->font_data_size
= font_data_size
;
1476 face
->face_index
= face_index
;
1478 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1479 face
->ntmFlags
|= NTM_ITALIC
;
1480 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1481 face
->ntmFlags
|= NTM_BOLD
;
1482 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1483 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1484 face
->family
= family
;
1485 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1487 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1489 if(FT_IS_SCALABLE(ft_face
)) {
1490 memset(&face
->size
, 0, sizeof(face
->size
));
1491 face
->scalable
= TRUE
;
1493 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1494 size
->height
, size
->width
, size
->size
>> 6,
1495 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1496 face
->size
.height
= size
->height
;
1497 face
->size
.width
= size
->width
;
1498 face
->size
.size
= size
->size
;
1499 face
->size
.x_ppem
= size
->x_ppem
;
1500 face
->size
.y_ppem
= size
->y_ppem
;
1501 face
->size
.internal_leading
= internal_leading
;
1502 face
->scalable
= FALSE
;
1505 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1507 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1509 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1510 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1513 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1514 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1515 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1516 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1519 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1520 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1521 switch(ft_face
->charmaps
[i
]->encoding
) {
1522 case FT_ENCODING_UNICODE
:
1523 case FT_ENCODING_APPLE_ROMAN
:
1524 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1526 case FT_ENCODING_MS_SYMBOL
:
1527 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1535 AddFaceToFamily(face
, family
);
1537 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1539 num_faces
= ft_face
->num_faces
;
1540 pFT_Done_Face(ft_face
);
1541 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1542 debugstr_w(StyleW
));
1543 } while(num_faces
> ++face_index
);
1547 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1549 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1552 static void DumpFontList(void)
1556 struct list
*family_elem_ptr
, *face_elem_ptr
;
1558 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1559 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1560 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1561 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1562 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1563 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1565 TRACE(" %d", face
->size
.height
);
1572 /***********************************************************
1573 * The replacement list is a way to map an entire font
1574 * family onto another family. For example adding
1576 * [HKCU\Software\Wine\Fonts\Replacements]
1577 * "Wingdings"="Winedings"
1579 * would enumerate the Winedings font both as Winedings and
1580 * Wingdings. However if a real Wingdings font is present the
1581 * replacement does not take place.
1584 static void LoadReplaceList(void)
1587 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1592 struct list
*family_elem_ptr
, *face_elem_ptr
;
1595 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1596 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1598 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1599 &valuelen
, &datalen
, NULL
, NULL
);
1601 valuelen
++; /* returned value doesn't include room for '\0' */
1602 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1603 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1607 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1608 &dlen
) == ERROR_SUCCESS
) {
1609 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1610 /* "NewName"="Oldname" */
1611 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1613 /* Find the old family and hence all of the font files
1615 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1616 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1617 if(!strcmpiW(family
->FamilyName
, data
)) {
1618 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1619 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1620 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1621 debugstr_w(face
->StyleName
), familyA
);
1622 /* Now add a new entry with the new family name */
1623 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1628 /* reset dlen and vlen */
1632 HeapFree(GetProcessHeap(), 0, data
);
1633 HeapFree(GetProcessHeap(), 0, value
);
1638 /*************************************************************
1641 static BOOL
init_system_links(void)
1645 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1646 WCHAR
*value
, *data
;
1647 WCHAR
*entry
, *next
;
1648 SYSTEM_LINKS
*font_link
, *system_font_link
;
1649 CHILD_FONT
*child_font
;
1650 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1651 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1657 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1659 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1660 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1661 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1662 val_len
= max_val
+ 1;
1663 data_len
= max_data
;
1665 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1667 memset(&fs
, 0, sizeof(fs
));
1668 psub
= get_font_subst(&font_subst_list
, value
, -1);
1669 /* Don't store fonts that are only substitutes for other fonts */
1672 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1675 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1676 font_link
->font_name
= strdupW(value
);
1677 list_init(&font_link
->links
);
1678 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1681 CHILD_FONT
*child_font
;
1683 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
1685 next
= entry
+ strlenW(entry
) + 1;
1687 face_name
= strchrW(entry
, ',');
1691 while(isspaceW(*face_name
))
1694 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1696 face_name
= psub
->to
.name
;
1698 face
= find_face_from_filename(entry
, face_name
);
1701 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1705 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1706 child_font
->face
= face
;
1707 child_font
->font
= NULL
;
1708 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1709 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1710 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1711 list_add_tail(&font_link
->links
, &child_font
->entry
);
1713 family
= find_family_from_name(font_link
->font_name
);
1716 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1718 face
->fs_links
= fs
;
1721 list_add_tail(&system_links
, &font_link
->entry
);
1723 val_len
= max_val
+ 1;
1724 data_len
= max_data
;
1727 HeapFree(GetProcessHeap(), 0, value
);
1728 HeapFree(GetProcessHeap(), 0, data
);
1732 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1735 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1736 system_font_link
->font_name
= strdupW(System
);
1737 list_init(&system_font_link
->links
);
1739 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1742 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1743 child_font
->face
= face
;
1744 child_font
->font
= NULL
;
1745 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1746 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1748 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1750 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1752 CHILD_FONT
*font_link_entry
;
1753 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1755 CHILD_FONT
*new_child
;
1756 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1757 new_child
->face
= font_link_entry
->face
;
1758 new_child
->font
= NULL
;
1759 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1764 list_add_tail(&system_links
, &system_font_link
->entry
);
1768 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1771 struct dirent
*dent
;
1772 char path
[MAX_PATH
];
1774 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1776 dir
= opendir(dirname
);
1778 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1781 while((dent
= readdir(dir
)) != NULL
) {
1782 struct stat statbuf
;
1784 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1787 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1789 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1791 if(stat(path
, &statbuf
) == -1)
1793 WARN("Can't stat %s\n", debugstr_a(path
));
1796 if(S_ISDIR(statbuf
.st_mode
))
1797 ReadFontDir(path
, external_fonts
);
1799 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1805 static void load_fontconfig_fonts(void)
1807 #ifdef SONAME_LIBFONTCONFIG
1808 void *fc_handle
= NULL
;
1817 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1819 TRACE("Wine cannot find the fontconfig library (%s).\n",
1820 SONAME_LIBFONTCONFIG
);
1823 #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;}
1824 LOAD_FUNCPTR(FcConfigGetCurrent
);
1825 LOAD_FUNCPTR(FcFontList
);
1826 LOAD_FUNCPTR(FcFontSetDestroy
);
1827 LOAD_FUNCPTR(FcInit
);
1828 LOAD_FUNCPTR(FcObjectSetAdd
);
1829 LOAD_FUNCPTR(FcObjectSetCreate
);
1830 LOAD_FUNCPTR(FcObjectSetDestroy
);
1831 LOAD_FUNCPTR(FcPatternCreate
);
1832 LOAD_FUNCPTR(FcPatternDestroy
);
1833 LOAD_FUNCPTR(FcPatternGetBool
);
1834 LOAD_FUNCPTR(FcPatternGetString
);
1837 if(!pFcInit()) return;
1839 config
= pFcConfigGetCurrent();
1840 pat
= pFcPatternCreate();
1841 os
= pFcObjectSetCreate();
1842 pFcObjectSetAdd(os
, FC_FILE
);
1843 pFcObjectSetAdd(os
, FC_SCALABLE
);
1844 fontset
= pFcFontList(config
, pat
, os
);
1845 if(!fontset
) return;
1846 for(i
= 0; i
< fontset
->nfont
; i
++) {
1849 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1851 TRACE("fontconfig: %s\n", file
);
1853 /* We're just interested in OT/TT fonts for now, so this hack just
1854 picks up the scalable fonts without extensions .pf[ab] to save time
1855 loading every other font */
1857 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1859 TRACE("not scalable\n");
1863 len
= strlen( file
);
1864 if(len
< 4) continue;
1865 ext
= &file
[ len
- 3 ];
1866 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1867 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1869 pFcFontSetDestroy(fontset
);
1870 pFcObjectSetDestroy(os
);
1871 pFcPatternDestroy(pat
);
1877 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1880 const char *data_dir
= wine_get_data_dir();
1882 if (!data_dir
) data_dir
= wine_get_build_dir();
1889 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1891 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1893 strcpy(unix_name
, data_dir
);
1894 strcat(unix_name
, "/fonts/");
1896 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1898 EnterCriticalSection( &freetype_cs
);
1899 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1900 LeaveCriticalSection( &freetype_cs
);
1901 HeapFree(GetProcessHeap(), 0, unix_name
);
1906 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1908 static const WCHAR slashW
[] = {'\\','\0'};
1910 WCHAR windowsdir
[MAX_PATH
];
1913 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1914 strcatW(windowsdir
, fontsW
);
1915 strcatW(windowsdir
, slashW
);
1916 strcatW(windowsdir
, file
);
1917 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1918 EnterCriticalSection( &freetype_cs
);
1919 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1920 LeaveCriticalSection( &freetype_cs
);
1921 HeapFree(GetProcessHeap(), 0, unixname
);
1926 static void load_system_fonts(void)
1929 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1930 const WCHAR
* const *value
;
1932 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1935 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1936 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1937 strcatW(windowsdir
, fontsW
);
1938 for(value
= SystemFontValues
; *value
; value
++) {
1939 dlen
= sizeof(data
);
1940 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1944 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1945 if((unixname
= wine_get_unix_file_name(pathW
))) {
1946 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1947 HeapFree(GetProcessHeap(), 0, unixname
);
1950 load_font_from_data_dir(data
);
1957 /*************************************************************
1959 * This adds registry entries for any externally loaded fonts
1960 * (fonts from fontconfig or FontDirs). It also deletes entries
1961 * of no longer existing fonts.
1964 static void update_reg_entries(void)
1966 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1971 struct list
*family_elem_ptr
, *face_elem_ptr
;
1973 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1974 static const WCHAR spaceW
[] = {' ', '\0'};
1977 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1978 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1979 ERR("Can't create Windows font reg key\n");
1983 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1984 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1985 ERR("Can't create Windows font reg key\n");
1989 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1990 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
1991 ERR("Can't create external font reg key\n");
1995 /* enumerate the fonts and add external ones to the two keys */
1997 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1998 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1999 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2000 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2001 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2002 if(!face
->external
) continue;
2004 if (!(face
->ntmFlags
& NTM_REGULAR
))
2005 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2006 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2007 strcpyW(valueW
, family
->FamilyName
);
2008 if(len
!= len_fam
) {
2009 strcatW(valueW
, spaceW
);
2010 strcatW(valueW
, face
->StyleName
);
2012 strcatW(valueW
, TrueType
);
2014 file
= wine_get_dos_file_name(face
->file
);
2016 len
= strlenW(file
) + 1;
2019 if((path
= strrchr(face
->file
, '/')) == NULL
)
2023 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2025 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2026 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2028 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2029 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2030 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2032 HeapFree(GetProcessHeap(), 0, file
);
2033 HeapFree(GetProcessHeap(), 0, valueW
);
2037 if(external_key
) RegCloseKey(external_key
);
2038 if(win9x_key
) RegCloseKey(win9x_key
);
2039 if(winnt_key
) RegCloseKey(winnt_key
);
2043 static void delete_external_font_keys(void)
2045 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2046 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2050 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2051 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2052 ERR("Can't create Windows font reg key\n");
2056 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2057 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2058 ERR("Can't create Windows font reg key\n");
2062 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2063 ERR("Can't create external font reg key\n");
2067 /* Delete all external fonts added last time */
2069 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2070 &valuelen
, &datalen
, NULL
, NULL
);
2071 valuelen
++; /* returned value doesn't include room for '\0' */
2072 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2073 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2075 dlen
= datalen
* sizeof(WCHAR
);
2078 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2079 &dlen
) == ERROR_SUCCESS
) {
2081 RegDeleteValueW(winnt_key
, valueW
);
2082 RegDeleteValueW(win9x_key
, valueW
);
2083 /* reset dlen and vlen */
2087 HeapFree(GetProcessHeap(), 0, data
);
2088 HeapFree(GetProcessHeap(), 0, valueW
);
2090 /* Delete the old external fonts key */
2091 RegCloseKey(external_key
);
2092 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2095 if(win9x_key
) RegCloseKey(win9x_key
);
2096 if(winnt_key
) RegCloseKey(winnt_key
);
2099 /*************************************************************
2100 * WineEngAddFontResourceEx
2103 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2109 if (ft_handle
) /* do it only if we have freetype up and running */
2114 FIXME("Ignoring flags %x\n", flags
);
2116 if((unixname
= wine_get_unix_file_name(file
)))
2118 EnterCriticalSection( &freetype_cs
);
2119 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2120 LeaveCriticalSection( &freetype_cs
);
2121 HeapFree(GetProcessHeap(), 0, unixname
);
2123 if (!ret
&& !strchrW(file
, '\\')) {
2124 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2125 ret
= load_font_from_winfonts_dir(file
);
2127 /* Try in datadir/fonts (or builddir/fonts),
2128 * needed for Magic the Gathering Online
2130 ret
= load_font_from_data_dir(file
);
2137 /*************************************************************
2138 * WineEngAddFontMemResourceEx
2141 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2145 if (ft_handle
) /* do it only if we have freetype up and running */
2147 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2149 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2150 memcpy(pFontCopy
, pbFont
, cbFont
);
2152 EnterCriticalSection( &freetype_cs
);
2153 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2154 LeaveCriticalSection( &freetype_cs
);
2158 TRACE("AddFontToList failed\n");
2159 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2162 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2163 * For now return something unique but quite random
2165 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2166 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2173 /*************************************************************
2174 * WineEngRemoveFontResourceEx
2177 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2180 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2184 static const struct nls_update_font_list
2186 UINT ansi_cp
, oem_cp
;
2187 const char *oem
, *fixed
, *system
;
2188 const char *courier
, *serif
, *small
, *sserif
;
2189 /* these are for font substitutes */
2190 const char *shelldlg
, *tmsrmn
;
2191 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2195 const char *from
, *to
;
2196 } arial_0
, courier_new_0
, times_new_roman_0
;
2197 } nls_update_font_list
[] =
2199 /* Latin 1 (United States) */
2200 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2201 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2202 "Tahoma","Times New Roman",
2203 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2206 /* Latin 1 (Multilingual) */
2207 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2208 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2209 "Tahoma","Times New Roman", /* FIXME unverified */
2210 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2213 /* Eastern Europe */
2214 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2215 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,238", "System,238",
2218 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2219 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2220 { "Arial CE,0", "Arial,238" },
2221 { "Courier New CE,0", "Courier New,238" },
2222 { "Times New Roman CE,0", "Times New Roman,238" }
2225 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2226 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 "Fixedsys,204", "System,204",
2229 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2230 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2231 { "Arial Cyr,0", "Arial,204" },
2232 { "Courier New Cyr,0", "Courier New,204" },
2233 { "Times New Roman Cyr,0", "Times New Roman,204" }
2236 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2237 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2238 "Tahoma","Times New Roman", /* FIXME unverified */
2239 "Fixedsys,161", "System,161",
2240 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2241 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2242 { "Arial Greek,0", "Arial,161" },
2243 { "Courier New Greek,0", "Courier New,161" },
2244 { "Times New Roman Greek,0", "Times New Roman,161" }
2247 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2248 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2249 "Tahoma","Times New Roman", /* FIXME unverified */
2250 "Fixedsys,162", "System,162",
2251 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2252 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2253 { "Arial Tur,0", "Arial,162" },
2254 { "Courier New Tur,0", "Courier New,162" },
2255 { "Times New Roman Tur,0", "Times New Roman,162" }
2258 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2259 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2260 "Tahoma","Times New Roman", /* FIXME unverified */
2261 "Fixedsys,177", "System,177",
2262 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2263 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2267 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2268 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2269 "Tahoma","Times New Roman", /* FIXME unverified */
2270 "Fixedsys,178", "System,178",
2271 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2272 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2276 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2277 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2278 "Tahoma","Times New Roman", /* FIXME unverified */
2279 "Fixedsys,186", "System,186",
2280 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2281 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2282 { "Arial Baltic,0", "Arial,186" },
2283 { "Courier New Baltic,0", "Courier New,186" },
2284 { "Times New Roman Baltic,0", "Times New Roman,186" }
2287 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2288 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2289 "Tahoma","Times New Roman", /* FIXME unverified */
2290 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2294 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2295 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2296 "Tahoma","Times New Roman", /* FIXME unverified */
2297 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2301 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2302 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2303 "MS UI Gothic","MS Serif",
2304 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2307 /* Chinese Simplified */
2308 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2309 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2310 "SimSun", "NSimSun",
2311 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2315 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2316 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2318 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2321 /* Chinese Traditional */
2322 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2323 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2324 "PMingLiU", "MingLiU",
2325 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2330 static const WCHAR
*font_links_list
[] =
2332 Lucida_Sans_Unicode
,
2333 Microsoft_Sans_Serif
,
2337 static const struct font_links_defaults_list
2339 /* Keyed off substitution for "MS Shell Dlg" */
2340 const WCHAR
*shelldlg
;
2341 /* Maximum of four substitutes, plus terminating NULL pointer */
2342 const WCHAR
*substitutes
[5];
2343 } font_links_defaults_list
[] =
2345 /* Non East-Asian */
2346 { Tahoma
, /* FIXME unverified ordering */
2347 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2349 /* Below lists are courtesy of
2350 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2354 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2356 /* Chinese Simplified */
2358 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2362 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2364 /* Chinese Traditional */
2366 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2370 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2372 return ( ansi_cp
== 932 /* CP932 for Japanese */
2373 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2374 || ansi_cp
== 949 /* CP949 for Korean */
2375 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2378 static inline HKEY
create_fonts_NT_registry_key(void)
2382 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2383 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2387 static inline HKEY
create_fonts_9x_registry_key(void)
2391 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2392 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2396 static inline HKEY
create_config_fonts_registry_key(void)
2400 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2401 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2405 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2407 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2408 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2409 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2410 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2413 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2416 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2418 RegDeleteValueA(hkey
, name
);
2421 static void update_font_info(void)
2423 char buf
[40], cpbuf
[40];
2426 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2429 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2432 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2433 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2434 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2435 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2436 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2438 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2439 if (is_dbcs_ansi_cp(ansi_cp
))
2440 use_default_fallback
= TRUE
;
2443 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2445 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2450 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2452 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2454 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2457 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2461 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2462 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2464 hkey
= create_config_fonts_registry_key();
2465 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2466 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2467 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2470 hkey
= create_fonts_NT_registry_key();
2471 add_font_list(hkey
, &nls_update_font_list
[i
]);
2474 hkey
= create_fonts_9x_registry_key();
2475 add_font_list(hkey
, &nls_update_font_list
[i
]);
2478 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2480 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2481 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2482 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2483 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2485 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2486 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2487 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2488 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2489 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2490 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2491 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2492 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2494 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2495 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2496 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2504 /* Delete the FontSubstitutes from other locales */
2505 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2507 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2508 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2509 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2515 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2517 /* Clear out system links */
2518 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, system_link
);
2521 static void populate_system_links(HKEY hkey
, const WCHAR
*name
, const WCHAR
*const *values
)
2531 WCHAR buff
[MAX_PATH
];
2535 static const WCHAR comma
[] = {',',0};
2537 RegDeleteValueW(hkey
, name
);
2542 for (i
= 0; values
[i
] != NULL
; i
++)
2545 if (!strcmpiW(name
,value
))
2547 psub
= get_font_subst(&font_subst_list
, value
, -1);
2549 value
= psub
->to
.name
;
2550 family
= find_family_from_name(value
);
2554 /* Use first extant filename for this Family */
2555 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2559 file
= strrchr(face
->file
, '/');
2568 fileLen
= MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, NULL
, 0);
2569 fileW
= HeapAlloc(GetProcessHeap(), 0, fileLen
* sizeof(WCHAR
));
2570 MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, fileW
, fileLen
);
2571 entryLen
= strlenW(fileW
) + 1 + strlenW(value
) + 1;
2572 if (sizeof(buff
)-(data
-buff
) < entryLen
+ 1)
2574 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name
));
2575 HeapFree(GetProcessHeap(), 0, fileW
);
2578 strcpyW(data
, fileW
);
2579 strcatW(data
, comma
);
2580 strcatW(data
, value
);
2582 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2583 HeapFree(GetProcessHeap(), 0, fileW
);
2589 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (BYTE
*)buff
, (data
-buff
) * sizeof(WCHAR
));
2591 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name
));
2593 TRACE("removed SystemLink for %s\n", debugstr_w(name
));
2596 static void update_system_links(void)
2604 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2606 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE
, system_link
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, &disposition
))
2608 if (disposition
== REG_OPENED_EXISTING_KEY
)
2610 TRACE("SystemLink key already exists, doing nothing\n");
2615 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2617 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2622 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2624 if (!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
))
2626 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2627 populate_system_links(hkey
, font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2629 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2630 populate_system_links(hkey
, psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2633 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2635 populate_system_links(hkey
, font_links_defaults_list
[i
].substitutes
[0], NULL
);
2640 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub
->to
.name
));
2642 WARN("failed to create SystemLink key\n");
2646 static BOOL
init_freetype(void)
2648 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2651 "Wine cannot find the FreeType font library. To enable Wine to\n"
2652 "use TrueType fonts please install a version of FreeType greater than\n"
2653 "or equal to 2.0.5.\n"
2654 "http://www.freetype.org\n");
2658 #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;}
2660 LOAD_FUNCPTR(FT_Vector_Unit
)
2661 LOAD_FUNCPTR(FT_Done_Face
)
2662 LOAD_FUNCPTR(FT_Get_Char_Index
)
2663 LOAD_FUNCPTR(FT_Get_Module
)
2664 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2665 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2666 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2667 LOAD_FUNCPTR(FT_Init_FreeType
)
2668 LOAD_FUNCPTR(FT_Load_Glyph
)
2669 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2670 #ifndef FT_MULFIX_INLINED
2671 LOAD_FUNCPTR(FT_MulFix
)
2673 LOAD_FUNCPTR(FT_New_Face
)
2674 LOAD_FUNCPTR(FT_New_Memory_Face
)
2675 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2676 LOAD_FUNCPTR(FT_Outline_Transform
)
2677 LOAD_FUNCPTR(FT_Outline_Translate
)
2678 LOAD_FUNCPTR(FT_Select_Charmap
)
2679 LOAD_FUNCPTR(FT_Set_Charmap
)
2680 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2681 LOAD_FUNCPTR(FT_Vector_Transform
)
2682 LOAD_FUNCPTR(FT_Render_Glyph
)
2685 /* Don't warn if these ones are missing */
2686 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2687 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2688 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2689 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2690 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2691 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2692 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
2694 #ifdef HAVE_FREETYPE_FTWINFNT_H
2695 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2697 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2698 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2699 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2700 <= 2.0.3 has FT_Sqrt64 */
2704 if(pFT_Init_FreeType(&library
) != 0) {
2705 ERR("Can't init FreeType library\n");
2706 wine_dlclose(ft_handle
, NULL
, 0);
2710 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2711 if (pFT_Library_Version
)
2712 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2714 if (FT_Version
.major
<=0)
2720 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2721 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2722 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2723 ((FT_Version
.patch
) & 0x0000ff);
2729 "Wine cannot find certain functions that it needs inside the FreeType\n"
2730 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2731 "FreeType to at least version 2.0.5.\n"
2732 "http://www.freetype.org\n");
2733 wine_dlclose(ft_handle
, NULL
, 0);
2738 /*************************************************************
2741 * Initialize FreeType library and create a list of available faces
2743 BOOL
WineEngInit(void)
2745 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2746 static const WCHAR pathW
[] = {'P','a','t','h',0};
2748 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2749 WCHAR windowsdir
[MAX_PATH
];
2752 const char *data_dir
;
2756 /* update locale dependent font info in registry */
2759 if(!init_freetype()) return FALSE
;
2761 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2762 ERR("Failed to create font mutex\n");
2765 WaitForSingleObject(font_mutex
, INFINITE
);
2767 delete_external_font_keys();
2769 /* load the system bitmap fonts */
2770 load_system_fonts();
2772 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2773 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2774 strcatW(windowsdir
, fontsW
);
2775 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2777 ReadFontDir(unixname
, FALSE
);
2778 HeapFree(GetProcessHeap(), 0, unixname
);
2781 /* load the system truetype fonts */
2782 data_dir
= wine_get_data_dir();
2783 if (!data_dir
) data_dir
= wine_get_build_dir();
2784 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2785 strcpy(unixname
, data_dir
);
2786 strcat(unixname
, "/fonts/");
2787 ReadFontDir(unixname
, TRUE
);
2788 HeapFree(GetProcessHeap(), 0, unixname
);
2791 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2792 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2793 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2795 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2796 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2797 &hkey
) == ERROR_SUCCESS
) {
2798 LPWSTR data
, valueW
;
2799 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2800 &valuelen
, &datalen
, NULL
, NULL
);
2802 valuelen
++; /* returned value doesn't include room for '\0' */
2803 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2804 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2807 dlen
= datalen
* sizeof(WCHAR
);
2809 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
2810 &dlen
) == ERROR_SUCCESS
) {
2811 if(data
[0] && (data
[1] == ':'))
2813 if((unixname
= wine_get_unix_file_name(data
)))
2815 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2816 HeapFree(GetProcessHeap(), 0, unixname
);
2819 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
2821 WCHAR pathW
[MAX_PATH
];
2822 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2825 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2826 if((unixname
= wine_get_unix_file_name(pathW
)))
2828 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2829 HeapFree(GetProcessHeap(), 0, unixname
);
2832 load_font_from_data_dir(data
);
2834 /* reset dlen and vlen */
2839 HeapFree(GetProcessHeap(), 0, data
);
2840 HeapFree(GetProcessHeap(), 0, valueW
);
2844 load_fontconfig_fonts();
2846 /* then look in any directories that we've specified in the config file */
2847 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2848 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2854 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2856 len
+= sizeof(WCHAR
);
2857 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2858 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2860 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2861 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2862 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2863 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2867 LPSTR next
= strchr( ptr
, ':' );
2868 if (next
) *next
++ = 0;
2869 ReadFontDir( ptr
, TRUE
);
2872 HeapFree( GetProcessHeap(), 0, valueA
);
2874 HeapFree( GetProcessHeap(), 0, valueW
);
2883 update_reg_entries();
2885 update_system_links();
2886 init_system_links();
2888 ReleaseMutex(font_mutex
);
2893 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2896 TT_HoriHeader
*pHori
;
2900 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2901 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2903 if(height
== 0) height
= 16;
2905 /* Calc. height of EM square:
2907 * For +ve lfHeight we have
2908 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2909 * Re-arranging gives:
2910 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2912 * For -ve lfHeight we have
2914 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2915 * with il = winAscent + winDescent - units_per_em]
2920 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2921 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2922 pHori
->Ascender
- pHori
->Descender
);
2924 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2925 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2933 static struct font_mapping
*map_font_file( const char *name
)
2935 struct font_mapping
*mapping
;
2939 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2940 if (fstat( fd
, &st
) == -1) goto error
;
2942 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2944 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2946 mapping
->refcount
++;
2951 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2954 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2957 if (mapping
->data
== MAP_FAILED
)
2959 HeapFree( GetProcessHeap(), 0, mapping
);
2962 mapping
->refcount
= 1;
2963 mapping
->dev
= st
.st_dev
;
2964 mapping
->ino
= st
.st_ino
;
2965 mapping
->size
= st
.st_size
;
2966 list_add_tail( &mappings_list
, &mapping
->entry
);
2974 static void unmap_font_file( struct font_mapping
*mapping
)
2976 if (!--mapping
->refcount
)
2978 list_remove( &mapping
->entry
);
2979 munmap( mapping
->data
, mapping
->size
);
2980 HeapFree( GetProcessHeap(), 0, mapping
);
2984 static LONG
load_VDMX(GdiFont
*, LONG
);
2986 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2993 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2997 if (!(font
->mapping
= map_font_file( face
->file
)))
2999 WARN("failed to map %s\n", debugstr_a(face
->file
));
3002 data_ptr
= font
->mapping
->data
;
3003 data_size
= font
->mapping
->size
;
3007 data_ptr
= face
->font_data_ptr
;
3008 data_size
= face
->font_data_size
;
3011 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3013 ERR("FT_New_Face rets %d\n", err
);
3017 /* set it here, as load_VDMX needs it */
3018 font
->ft_face
= ft_face
;
3020 if(FT_IS_SCALABLE(ft_face
)) {
3021 /* load the VDMX table if we have one */
3022 font
->ppem
= load_VDMX(font
, height
);
3024 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3025 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3027 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3028 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3030 font
->ppem
= height
;
3031 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3032 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3038 static int get_nearest_charset(Face
*face
, int *cp
)
3040 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3041 a single face with the requested charset. The idea is to check if
3042 the selected font supports the current ANSI codepage, if it does
3043 return the corresponding charset, else return the first charset */
3046 int acp
= GetACP(), i
;
3050 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3051 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3052 return csi
.ciCharset
;
3054 for(i
= 0; i
< 32; i
++) {
3056 if(face
->fs
.fsCsb
[0] & fs0
) {
3057 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3059 return csi
.ciCharset
;
3062 FIXME("TCI failing on %x\n", fs0
);
3066 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3067 face
->fs
.fsCsb
[0], face
->file
);
3069 return DEFAULT_CHARSET
;
3072 static GdiFont
*alloc_font(void)
3074 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3076 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3077 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3079 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3080 ret
->total_kern_pairs
= (DWORD
)-1;
3081 ret
->kern_pairs
= NULL
;
3082 list_init(&ret
->hfontlist
);
3083 list_init(&ret
->child_fonts
);
3087 static void free_font(GdiFont
*font
)
3089 struct list
*cursor
, *cursor2
;
3092 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3094 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3095 list_remove(cursor
);
3097 free_font(child
->font
);
3098 HeapFree(GetProcessHeap(), 0, child
);
3101 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3103 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3104 DeleteObject(hfontlist
->hfont
);
3105 list_remove(&hfontlist
->entry
);
3106 HeapFree(GetProcessHeap(), 0, hfontlist
);
3109 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3110 if (font
->mapping
) unmap_font_file( font
->mapping
);
3111 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3112 HeapFree(GetProcessHeap(), 0, font
->potm
);
3113 HeapFree(GetProcessHeap(), 0, font
->name
);
3114 for (i
= 0; i
< font
->gmsize
; i
++)
3115 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3116 HeapFree(GetProcessHeap(), 0, font
->gm
);
3117 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3118 HeapFree(GetProcessHeap(), 0, font
);
3122 /*************************************************************
3125 * load the vdmx entry for the specified height
3128 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3129 ( ( (FT_ULong)_x4 << 24 ) | \
3130 ( (FT_ULong)_x3 << 16 ) | \
3131 ( (FT_ULong)_x2 << 8 ) | \
3134 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3149 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3153 BYTE devXRatio
, devYRatio
;
3154 USHORT numRecs
, numRatios
;
3155 DWORD result
, offset
= -1;
3159 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3161 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3164 /* FIXME: need the real device aspect ratio */
3168 numRecs
= GET_BE_WORD(hdr
[1]);
3169 numRatios
= GET_BE_WORD(hdr
[2]);
3171 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3172 for(i
= 0; i
< numRatios
; i
++) {
3175 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3176 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3179 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3181 if((ratio
.xRatio
== 0 &&
3182 ratio
.yStartRatio
== 0 &&
3183 ratio
.yEndRatio
== 0) ||
3184 (devXRatio
== ratio
.xRatio
&&
3185 devYRatio
>= ratio
.yStartRatio
&&
3186 devYRatio
<= ratio
.yEndRatio
))
3188 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3189 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3190 offset
= GET_BE_WORD(tmp
);
3196 FIXME("No suitable ratio found\n");
3200 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3202 BYTE startsz
, endsz
;
3205 recs
= GET_BE_WORD(group
.recs
);
3206 startsz
= group
.startsz
;
3207 endsz
= group
.endsz
;
3209 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3211 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3212 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3213 if(result
== GDI_ERROR
) {
3214 FIXME("Failed to retrieve vTable\n");
3219 for(i
= 0; i
< recs
; i
++) {
3220 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3221 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3222 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3224 if(yMax
+ -yMin
== height
) {
3227 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3230 if(yMax
+ -yMin
> height
) {
3233 goto end
; /* failed */
3235 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3236 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3237 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3238 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3244 TRACE("ppem not found for height %d\n", height
);
3248 HeapFree(GetProcessHeap(), 0, vTable
);
3254 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3256 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3257 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3258 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3259 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3260 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3263 static void calc_hash(FONT_DESC
*pfd
)
3265 DWORD hash
= 0, *ptr
, two_chars
;
3269 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3271 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3273 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3275 pwc
= (WCHAR
*)&two_chars
;
3277 *pwc
= toupperW(*pwc
);
3279 *pwc
= toupperW(*pwc
);
3283 hash
^= !pfd
->can_use_bitmap
;
3288 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3293 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3297 fd
.can_use_bitmap
= can_use_bitmap
;
3300 /* try the child list */
3301 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3302 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3303 if(!fontcmp(ret
, &fd
)) {
3304 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3305 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3306 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3307 if(hflist
->hfont
== hfont
)
3313 /* try the in-use list */
3314 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3315 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3316 if(!fontcmp(ret
, &fd
)) {
3317 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3318 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3319 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3320 if(hflist
->hfont
== hfont
)
3323 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3324 hflist
->hfont
= hfont
;
3325 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3330 /* then the unused list */
3331 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3332 while(font_elem_ptr
) {
3333 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3334 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3335 if(!fontcmp(ret
, &fd
)) {
3336 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3337 assert(list_empty(&ret
->hfontlist
));
3338 TRACE("Found %p in unused list\n", ret
);
3339 list_remove(&ret
->entry
);
3340 list_add_head(&gdi_font_list
, &ret
->entry
);
3341 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3342 hflist
->hfont
= hfont
;
3343 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3350 static void add_to_cache(GdiFont
*font
)
3352 static DWORD cache_num
= 1;
3354 font
->cache_num
= cache_num
++;
3355 list_add_head(&gdi_font_list
, &font
->entry
);
3358 /*************************************************************
3359 * create_child_font_list
3361 static BOOL
create_child_font_list(GdiFont
*font
)
3364 SYSTEM_LINKS
*font_link
;
3365 CHILD_FONT
*font_link_entry
, *new_child
;
3369 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3370 font_name
= psub
? psub
->to
.name
: font
->name
;
3371 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3373 if(!strcmpiW(font_link
->font_name
, font_name
))
3375 TRACE("found entry in system list\n");
3376 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3378 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3379 new_child
->face
= font_link_entry
->face
;
3380 new_child
->font
= NULL
;
3381 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3382 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3389 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3390 * Sans Serif. This is how asian windows get default fallbacks for fonts
3392 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3393 font
->charset
!= OEM_CHARSET
&&
3394 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3395 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3397 if(!strcmpiW(font_link
->font_name
,szDefaultFallbackLink
))
3399 TRACE("found entry in default fallback list\n");
3400 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3402 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3403 new_child
->face
= font_link_entry
->face
;
3404 new_child
->font
= NULL
;
3405 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3406 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3416 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3418 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3420 if (pFT_Set_Charmap
)
3423 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3425 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3427 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3429 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3431 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3432 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3434 switch (ft_face
->charmaps
[i
]->platform_id
)
3437 cmap_def
= ft_face
->charmaps
[i
];
3439 case 0: /* Apple Unicode */
3440 cmap0
= ft_face
->charmaps
[i
];
3442 case 1: /* Macintosh */
3443 cmap1
= ft_face
->charmaps
[i
];
3446 cmap2
= ft_face
->charmaps
[i
];
3448 case 3: /* Microsoft */
3449 cmap3
= ft_face
->charmaps
[i
];
3454 if (cmap3
) /* prefer Microsoft cmap table */
3455 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3457 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3459 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3461 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3463 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3465 return ft_err
== FT_Err_Ok
;
3468 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3471 /*************************************************************
3472 * WineEngCreateFontInstance
3475 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3478 Face
*face
, *best
, *best_bitmap
;
3479 Family
*family
, *last_resort_family
;
3480 struct list
*family_elem_ptr
, *face_elem_ptr
;
3481 INT height
, width
= 0;
3482 unsigned int score
= 0, new_score
;
3483 signed int diff
= 0, newdiff
;
3484 BOOL bd
, it
, can_use_bitmap
;
3489 FontSubst
*psub
= NULL
;
3491 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3492 lf
.lfWidth
= abs(lf
.lfWidth
);
3494 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3496 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3497 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3498 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3501 if(dc
->GraphicsMode
== GM_ADVANCED
)
3502 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3505 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3506 font scaling abilities. */
3507 dcmat
.eM11
= dcmat
.eM22
= dc
->vport2WorldValid
? fabs(dc
->xformWorld2Vport
.eM22
) : 1.0;
3508 dcmat
.eM21
= dcmat
.eM12
= 0;
3511 /* Try to avoid not necessary glyph transformations */
3512 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3514 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3515 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3516 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3519 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3520 dcmat
.eM21
, dcmat
.eM22
);
3523 EnterCriticalSection( &freetype_cs
);
3525 /* check the cache first */
3526 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3527 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3528 LeaveCriticalSection( &freetype_cs
);
3532 TRACE("not in cache\n");
3533 if(list_empty(&font_list
)) /* No fonts installed */
3535 TRACE("No fonts installed\n");
3536 LeaveCriticalSection( &freetype_cs
);
3542 ret
->font_desc
.matrix
= dcmat
;
3543 ret
->font_desc
.lf
= lf
;
3544 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3545 calc_hash(&ret
->font_desc
);
3546 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3547 hflist
->hfont
= hfont
;
3548 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3550 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3551 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3552 original value lfCharSet. Note this is a special case for
3553 Symbol and doesn't happen at least for "Wingdings*" */
3555 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3556 lf
.lfCharSet
= SYMBOL_CHARSET
;
3558 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3559 switch(lf
.lfCharSet
) {
3560 case DEFAULT_CHARSET
:
3561 csi
.fs
.fsCsb
[0] = 0;
3564 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3565 csi
.fs
.fsCsb
[0] = 0;
3571 if(lf
.lfFaceName
[0] != '\0') {
3572 SYSTEM_LINKS
*font_link
;
3573 CHILD_FONT
*font_link_entry
;
3574 LPWSTR FaceName
= lf
.lfFaceName
;
3577 * Check for a leading '@' this signals that the font is being
3578 * requested in tategaki mode (vertical writing substitution) but
3579 * does not affect the fontface that is to be selected.
3581 if (lf
.lfFaceName
[0]=='@')
3582 FaceName
= &lf
.lfFaceName
[1];
3584 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3587 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
3588 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
3589 if (psub
->to
.charset
!= -1)
3590 lf
.lfCharSet
= psub
->to
.charset
;
3593 /* We want a match on name and charset or just name if
3594 charset was DEFAULT_CHARSET. If the latter then
3595 we fixup the returned charset later in get_nearest_charset
3596 where we'll either use the charset of the current ansi codepage
3597 or if that's unavailable the first charset that the font supports.
3599 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3600 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3601 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
3602 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
3604 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3605 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3606 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3607 if(face
->scalable
|| can_use_bitmap
)
3614 * Try check the SystemLink list first for a replacement font.
3615 * We may find good replacements there.
3617 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3619 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
3620 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
3622 TRACE("found entry in system list\n");
3623 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3625 face
= font_link_entry
->face
;
3626 family
= face
->family
;
3627 if(csi
.fs
.fsCsb
[0] &
3628 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3630 if(face
->scalable
|| can_use_bitmap
)
3638 psub
= NULL
; /* substitution is no more relevant */
3640 /* If requested charset was DEFAULT_CHARSET then try using charset
3641 corresponding to the current ansi codepage */
3642 if (!csi
.fs
.fsCsb
[0])
3645 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3646 FIXME("TCI failed on codepage %d\n", acp
);
3647 csi
.fs
.fsCsb
[0] = 0;
3649 lf
.lfCharSet
= csi
.ciCharset
;
3652 /* Face families are in the top 4 bits of lfPitchAndFamily,
3653 so mask with 0xF0 before testing */
3655 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3656 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3657 strcpyW(lf
.lfFaceName
, defFixed
);
3658 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3659 strcpyW(lf
.lfFaceName
, defSerif
);
3660 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3661 strcpyW(lf
.lfFaceName
, defSans
);
3663 strcpyW(lf
.lfFaceName
, defSans
);
3664 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3665 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3666 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3667 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3668 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3669 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3670 if(face
->scalable
|| can_use_bitmap
)
3676 last_resort_family
= NULL
;
3677 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3678 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3679 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3680 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3681 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3684 if(can_use_bitmap
&& !last_resort_family
)
3685 last_resort_family
= family
;
3690 if(last_resort_family
) {
3691 family
= last_resort_family
;
3692 csi
.fs
.fsCsb
[0] = 0;
3696 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3697 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3698 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3699 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3700 if(face
->scalable
) {
3701 csi
.fs
.fsCsb
[0] = 0;
3702 WARN("just using first face for now\n");
3705 if(can_use_bitmap
&& !last_resort_family
)
3706 last_resort_family
= family
;
3709 if(!last_resort_family
) {
3710 FIXME("can't find a single appropriate font - bailing\n");
3712 LeaveCriticalSection( &freetype_cs
);
3716 WARN("could only find a bitmap font - this will probably look awful!\n");
3717 family
= last_resort_family
;
3718 csi
.fs
.fsCsb
[0] = 0;
3721 it
= lf
.lfItalic
? 1 : 0;
3722 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3724 height
= lf
.lfHeight
;
3726 face
= best
= best_bitmap
= NULL
;
3727 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3729 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3733 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3734 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3735 new_score
= (italic
^ it
) + (bold
^ bd
);
3736 if(!best
|| new_score
<= score
)
3738 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3739 italic
, bold
, it
, bd
);
3742 if(best
->scalable
&& score
== 0) break;
3746 newdiff
= height
- (signed int)(best
->size
.height
);
3748 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3749 if(!best_bitmap
|| new_score
< score
||
3750 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3752 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3755 if(score
== 0 && diff
== 0) break;
3762 face
= best
->scalable
? best
: best_bitmap
;
3763 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3764 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3768 if(csi
.fs
.fsCsb
[0]) {
3769 ret
->charset
= lf
.lfCharSet
;
3770 ret
->codepage
= csi
.ciACP
;
3773 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3775 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3776 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3778 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3780 if(!face
->scalable
) {
3781 /* Windows uses integer scaling factors for bitmap fonts */
3782 INT scale
, scaled_height
;
3783 GdiFont
*cachedfont
;
3785 /* FIXME: rotation of bitmap fonts is ignored */
3786 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
3788 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
3789 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3790 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3791 /* As we changed the matrix, we need to search the cache for the font again,
3792 * otherwise we might explode the cache. */
3793 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3794 TRACE("Found cached font after non-scalable matrix rescale!\n");
3796 LeaveCriticalSection( &freetype_cs
);
3799 calc_hash(&ret
->font_desc
);
3801 if (height
!= 0) height
= diff
;
3802 height
+= face
->size
.height
;
3804 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3805 scaled_height
= scale
* face
->size
.height
;
3806 /* Only jump to the next height if the difference <= 25% original height */
3807 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
3808 /* The jump between unscaled and doubled is delayed by 1 */
3809 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
3810 ret
->scale_y
= scale
;
3812 width
= face
->size
.x_ppem
>> 6;
3813 height
= face
->size
.y_ppem
>> 6;
3817 TRACE("font scale y: %f\n", ret
->scale_y
);
3819 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3824 LeaveCriticalSection( &freetype_cs
);
3828 ret
->ntmFlags
= face
->ntmFlags
;
3830 if (ret
->charset
== SYMBOL_CHARSET
&&
3831 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3834 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3838 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3841 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3842 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
3843 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3844 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3845 create_child_font_list(ret
);
3847 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3849 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3850 if (length
!= GDI_ERROR
)
3852 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3853 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3854 TRACE("Loaded GSUB table of %i bytes\n",length
);
3858 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3861 LeaveCriticalSection( &freetype_cs
);
3865 static void dump_gdi_font_list(void)
3868 struct list
*elem_ptr
;
3870 TRACE("---------- gdiFont Cache ----------\n");
3871 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3872 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3873 TRACE("gdiFont=%p %s %d\n",
3874 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3877 TRACE("---------- Unused gdiFont Cache ----------\n");
3878 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3879 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3880 TRACE("gdiFont=%p %s %d\n",
3881 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3884 TRACE("---------- Child gdiFont Cache ----------\n");
3885 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
3886 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3887 TRACE("gdiFont=%p %s %d\n",
3888 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3892 /*************************************************************
3893 * WineEngDestroyFontInstance
3895 * free the gdiFont associated with this handle
3898 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3903 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3907 EnterCriticalSection( &freetype_cs
);
3909 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3911 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3912 while(hfontlist_elem_ptr
) {
3913 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3914 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3915 if(hflist
->hfont
== handle
) {
3916 TRACE("removing child font %p from child list\n", gdiFont
);
3917 list_remove(&gdiFont
->entry
);
3918 LeaveCriticalSection( &freetype_cs
);
3924 TRACE("destroying hfont=%p\n", handle
);
3926 dump_gdi_font_list();
3928 font_elem_ptr
= list_head(&gdi_font_list
);
3929 while(font_elem_ptr
) {
3930 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3931 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3933 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3934 while(hfontlist_elem_ptr
) {
3935 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3936 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3937 if(hflist
->hfont
== handle
) {
3938 list_remove(&hflist
->entry
);
3939 HeapFree(GetProcessHeap(), 0, hflist
);
3943 if(list_empty(&gdiFont
->hfontlist
)) {
3944 TRACE("Moving to Unused list\n");
3945 list_remove(&gdiFont
->entry
);
3946 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3951 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3952 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3953 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3954 while(font_elem_ptr
) {
3955 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3956 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3957 TRACE("freeing %p\n", gdiFont
);
3958 list_remove(&gdiFont
->entry
);
3961 LeaveCriticalSection( &freetype_cs
);
3965 /***************************************************
3966 * create_enum_charset_list
3968 * This function creates charset enumeration list because in DEFAULT_CHARSET
3969 * case, the ANSI codepage's charset takes precedence over other charsets.
3970 * This function works as a filter other than DEFAULT_CHARSET case.
3972 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
3977 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
3978 csi
.fs
.fsCsb
[0] != 0) {
3979 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
3980 list
->element
[n
].charset
= csi
.ciCharset
;
3981 list
->element
[n
].name
= ElfScriptsW
[ffs(csi
.fs
.fsCsb
[0]) - 1];
3984 else { /* charset is DEFAULT_CHARSET or invalid. */
3987 /* Set the current codepage's charset as the first element. */
3989 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
3990 csi
.fs
.fsCsb
[0] != 0) {
3991 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
3992 list
->element
[n
].charset
= csi
.ciCharset
;
3993 list
->element
[n
].name
= ElfScriptsW
[ffs(csi
.fs
.fsCsb
[0]) - 1];
3997 /* Fill out left elements. */
3998 for (i
= 0; i
< 32; i
++) {
4000 fs
.fsCsb
[0] = 1L << i
;
4002 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4003 continue; /* skip, already added. */
4004 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4005 continue; /* skip, this is an invalid fsCsb bit. */
4007 list
->element
[n
].mask
= fs
.fsCsb
[0];
4008 list
->element
[n
].charset
= csi
.ciCharset
;
4009 list
->element
[n
].name
= ElfScriptsW
[i
];
4018 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4019 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4024 if (face
->cached_enum_data
)
4027 *pelf
= face
->cached_enum_data
->elf
;
4028 *pntm
= face
->cached_enum_data
->ntm
;
4029 *ptype
= face
->cached_enum_data
->type
;
4033 font
= alloc_font();
4035 if(face
->scalable
) {
4036 height
= -2048; /* 2048 is the most common em size */
4039 height
= face
->size
.y_ppem
>> 6;
4040 width
= face
->size
.x_ppem
>> 6;
4042 font
->scale_y
= 1.0;
4044 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4050 font
->name
= strdupW(face
->family
->FamilyName
);
4051 font
->ntmFlags
= face
->ntmFlags
;
4053 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4055 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4057 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4059 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4060 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4062 lstrcpynW(pelf
->elfFullName
,
4063 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
4065 lstrcpynW(pelf
->elfStyle
,
4066 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4071 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4073 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4075 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4076 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4077 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4080 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4081 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4082 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4083 pntm
->ntmFontSig
= face
->fs
;
4085 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4087 pelf
->elfLogFont
.lfEscapement
= 0;
4088 pelf
->elfLogFont
.lfOrientation
= 0;
4089 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4090 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4091 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4092 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4093 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4094 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4095 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4096 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4097 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4098 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4099 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4102 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4103 *ptype
|= TRUETYPE_FONTTYPE
;
4104 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4105 *ptype
|= DEVICE_FONTTYPE
;
4106 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4107 *ptype
|= RASTER_FONTTYPE
;
4109 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4110 if (face
->cached_enum_data
)
4112 face
->cached_enum_data
->elf
= *pelf
;
4113 face
->cached_enum_data
->ntm
= *pntm
;
4114 face
->cached_enum_data
->type
= *ptype
;
4120 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4122 struct list
*face_elem_ptr
;
4124 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4126 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
)
4128 static const WCHAR spaceW
[] = { ' ',0 };
4129 WCHAR full_family_name
[LF_FULLFACESIZE
];
4130 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4132 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4134 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4135 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4139 strcpyW(full_family_name
, family
->FamilyName
);
4140 strcatW(full_family_name
, spaceW
);
4141 strcatW(full_family_name
, face
->StyleName
);
4142 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4148 static BOOL
face_matches(Face
*face
, const LOGFONTW
*lf
)
4150 static const WCHAR spaceW
[] = { ' ',0 };
4151 WCHAR full_family_name
[LF_FULLFACESIZE
];
4153 if (!strcmpiW(lf
->lfFaceName
, face
->family
->FamilyName
)) return TRUE
;
4155 if (strlenW(face
->family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4157 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4158 debugstr_w(face
->family
->FamilyName
), debugstr_w(face
->StyleName
));
4162 strcpyW(full_family_name
, face
->family
->FamilyName
);
4163 strcatW(full_family_name
, spaceW
);
4164 strcatW(full_family_name
, face
->StyleName
);
4165 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4168 static BOOL
enum_face_charsets(Face
*face
, struct enum_charset_list
*list
,
4169 FONTENUMPROCW proc
, LPARAM lparam
)
4172 NEWTEXTMETRICEXW ntm
;
4176 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4177 for(i
= 0; i
< list
->total
; i
++) {
4178 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4179 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4180 strcpyW(elf
.elfScript
, OEM_DOSW
);
4181 i
= 32; /* break out of loop */
4182 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4185 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4186 if(list
->element
[i
].name
)
4187 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4189 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4191 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4192 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4193 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4194 list
->element
[i
].charset
, type
, debugstr_w(elf
.elfScript
),
4195 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4196 ntm
.ntmTm
.ntmFlags
);
4197 /* release section before callback (FIXME) */
4198 LeaveCriticalSection( &freetype_cs
);
4199 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4200 EnterCriticalSection( &freetype_cs
);
4205 /*************************************************************
4209 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4213 struct list
*family_elem_ptr
, *face_elem_ptr
;
4215 struct enum_charset_list enum_charsets
;
4219 lf
.lfCharSet
= DEFAULT_CHARSET
;
4220 lf
.lfPitchAndFamily
= 0;
4221 lf
.lfFaceName
[0] = 0;
4225 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4227 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4230 EnterCriticalSection( &freetype_cs
);
4231 if(plf
->lfFaceName
[0]) {
4233 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4236 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4237 debugstr_w(psub
->to
.name
));
4239 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4243 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4244 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4245 if(family_matches(family
, plf
)) {
4246 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4247 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4248 if (!face_matches(face
, plf
)) continue;
4249 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return 0;
4254 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4255 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4256 face_elem_ptr
= list_head(&family
->faces
);
4257 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4258 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return 0;
4261 LeaveCriticalSection( &freetype_cs
);
4265 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4267 pt
->x
.value
= vec
->x
>> 6;
4268 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4269 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4270 pt
->y
.value
= vec
->y
>> 6;
4271 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4272 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4276 /***************************************************
4277 * According to the MSDN documentation on WideCharToMultiByte,
4278 * certain codepages cannot set the default_used parameter.
4279 * This returns TRUE if the codepage can set that parameter, false else
4280 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4282 static BOOL
codepage_sets_default_used(UINT codepage
)
4296 * GSUB Table handling functions
4299 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4301 const GSUB_CoverageFormat1
* cf1
;
4305 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4307 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4309 TRACE("Coverage Format 1, %i glyphs\n",count
);
4310 for (i
= 0; i
< count
; i
++)
4311 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4315 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4317 const GSUB_CoverageFormat2
* cf2
;
4320 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4322 count
= GET_BE_WORD(cf2
->RangeCount
);
4323 TRACE("Coverage Format 2, %i ranges\n",count
);
4324 for (i
= 0; i
< count
; i
++)
4326 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4328 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4329 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4331 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4332 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4338 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4343 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4345 const GSUB_ScriptList
*script
;
4346 const GSUB_Script
*deflt
= NULL
;
4348 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4350 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4351 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4353 const GSUB_Script
*scr
;
4356 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4357 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4359 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4361 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4367 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4371 const GSUB_LangSys
*Lang
;
4373 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4375 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4377 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4378 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4380 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4383 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4386 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4392 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4395 const GSUB_FeatureList
*feature
;
4396 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4398 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4399 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4401 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4402 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4404 const GSUB_Feature
*feat
;
4405 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4412 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4416 const GSUB_LookupList
*lookup
;
4417 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4419 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4420 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4422 const GSUB_LookupTable
*look
;
4423 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4424 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4425 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4426 if (GET_BE_WORD(look
->LookupType
) != 1)
4427 FIXME("We only handle SubType 1\n");
4432 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4434 const GSUB_SingleSubstFormat1
*ssf1
;
4435 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4436 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4437 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4439 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4440 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4441 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4443 TRACE(" Glyph 0x%x ->",glyph
);
4444 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4445 TRACE(" 0x%x\n",glyph
);
4450 const GSUB_SingleSubstFormat2
*ssf2
;
4454 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
4455 offset
= GET_BE_WORD(ssf1
->Coverage
);
4456 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4457 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
4458 TRACE(" Coverage index %i\n",index
);
4461 TRACE(" Glyph is 0x%x ->",glyph
);
4462 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4463 TRACE("0x%x\n",glyph
);
4472 static const char* get_opentype_script(const GdiFont
*font
)
4475 * I am not sure if this is the correct way to generate our script tag
4478 switch (font
->charset
)
4480 case ANSI_CHARSET
: return "latn";
4481 case BALTIC_CHARSET
: return "latn"; /* ?? */
4482 case CHINESEBIG5_CHARSET
: return "hani";
4483 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4484 case GB2312_CHARSET
: return "hani";
4485 case GREEK_CHARSET
: return "grek";
4486 case HANGUL_CHARSET
: return "hang";
4487 case RUSSIAN_CHARSET
: return "cyrl";
4488 case SHIFTJIS_CHARSET
: return "kana";
4489 case TURKISH_CHARSET
: return "latn"; /* ?? */
4490 case VIETNAMESE_CHARSET
: return "latn";
4491 case JOHAB_CHARSET
: return "latn"; /* ?? */
4492 case ARABIC_CHARSET
: return "arab";
4493 case HEBREW_CHARSET
: return "hebr";
4494 case THAI_CHARSET
: return "thai";
4495 default: return "latn";
4499 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4501 const GSUB_Header
*header
;
4502 const GSUB_Script
*script
;
4503 const GSUB_LangSys
*language
;
4504 const GSUB_Feature
*feature
;
4506 if (!font
->GSUB_Table
)
4509 header
= font
->GSUB_Table
;
4511 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4514 TRACE("Script not found\n");
4517 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4520 TRACE("Language not found\n");
4523 feature
= GSUB_get_feature(header
, language
, "vrt2");
4525 feature
= GSUB_get_feature(header
, language
, "vert");
4528 TRACE("vrt2/vert feature not found\n");
4531 return GSUB_apply_feature(header
, feature
, glyph
);
4534 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4538 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4539 WCHAR wc
= (WCHAR
)glyph
;
4541 BOOL
*default_used_pointer
;
4544 default_used_pointer
= NULL
;
4545 default_used
= FALSE
;
4546 if (codepage_sets_default_used(font
->codepage
))
4547 default_used_pointer
= &default_used
;
4548 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4551 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4552 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4553 return get_GSUB_vert_glyph(font
,ret
);
4556 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
&& glyph
< 0x100)
4557 glyph
= glyph
+ 0xf000;
4558 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4559 return get_GSUB_vert_glyph(font
,glyphId
);
4562 /*************************************************************
4563 * WineEngGetGlyphIndices
4566 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4567 LPWORD pgi
, DWORD flags
)
4570 int default_char
= -1;
4572 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4574 for(i
= 0; i
< count
; i
++)
4576 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4579 if (default_char
== -1)
4581 if (FT_IS_SFNT(font
->ft_face
))
4583 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4584 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4589 WineEngGetTextMetrics(font
, &textm
);
4590 default_char
= textm
.tmDefaultChar
;
4593 pgi
[i
] = default_char
;
4599 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
4601 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
4602 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
4605 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
4607 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
4608 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
4611 /*************************************************************
4612 * WineEngGetGlyphOutline
4614 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4615 * except that the first parameter is the HWINEENGFONT of the font in
4616 * question rather than an HDC.
4619 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4620 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4623 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4624 FT_Face ft_face
= incoming_font
->ft_face
;
4625 GdiFont
*font
= incoming_font
;
4626 FT_UInt glyph_index
;
4627 DWORD width
, height
, pitch
, needed
= 0;
4628 FT_Bitmap ft_bitmap
;
4630 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4632 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4633 double widthRatio
= 1.0;
4634 FT_Matrix transMat
= identityMat
;
4635 FT_Matrix transMatUnrotated
;
4636 BOOL needsTransform
= FALSE
;
4637 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4638 UINT original_index
;
4640 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4641 buflen
, buf
, lpmat
);
4643 TRACE("font transform %f %f %f %f\n",
4644 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
4645 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
4648 EnterCriticalSection( &freetype_cs
);
4650 if(format
& GGO_GLYPH_INDEX
) {
4651 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4652 original_index
= glyph
;
4653 format
&= ~GGO_GLYPH_INDEX
;
4655 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4656 ft_face
= font
->ft_face
;
4657 original_index
= glyph_index
;
4660 if(format
& GGO_UNHINTED
) {
4661 load_flags
|= FT_LOAD_NO_HINTING
;
4662 format
&= ~GGO_UNHINTED
;
4665 /* tategaki never appears to happen to lower glyph index */
4666 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4669 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4670 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4671 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4672 font
->gmsize
* sizeof(GM
*));
4674 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
4675 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
4677 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4678 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4679 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4680 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4681 LeaveCriticalSection( &freetype_cs
);
4682 return 1; /* FIXME */
4686 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4687 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4689 /* Scaling factor */
4694 WineEngGetTextMetrics(font
, &tm
);
4696 widthRatio
= (double)font
->aveWidth
;
4697 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4700 widthRatio
= font
->scale_y
;
4702 /* Scaling transform */
4703 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
4706 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4709 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4711 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4712 needsTransform
= TRUE
;
4715 /* Slant transform */
4716 if (font
->fake_italic
) {
4719 slantMat
.xx
= (1 << 16);
4720 slantMat
.xy
= ((1 << 16) >> 2);
4722 slantMat
.yy
= (1 << 16);
4723 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4724 needsTransform
= TRUE
;
4727 /* Rotation transform */
4728 transMatUnrotated
= transMat
;
4729 if(font
->orientation
&& !tategaki
) {
4730 FT_Matrix rotationMat
;
4732 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
4733 pFT_Vector_Unit(&vecAngle
, angle
);
4734 rotationMat
.xx
= vecAngle
.x
;
4735 rotationMat
.xy
= -vecAngle
.y
;
4736 rotationMat
.yx
= -rotationMat
.xy
;
4737 rotationMat
.yy
= rotationMat
.xx
;
4739 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4740 needsTransform
= TRUE
;
4743 /* World transform */
4744 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
4747 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
4748 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
4749 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
4750 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
4751 pFT_Matrix_Multiply(&worldMat
, &transMat
);
4752 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
4753 needsTransform
= TRUE
;
4756 /* Extra transformation specified by caller */
4757 if (!is_identity_MAT2(lpmat
))
4760 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4761 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
4762 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
4763 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4764 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4765 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
4766 needsTransform
= TRUE
;
4769 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4770 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4771 format
== GGO_GRAY8_BITMAP
))
4773 load_flags
|= FT_LOAD_NO_BITMAP
;
4776 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4779 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4780 LeaveCriticalSection( &freetype_cs
);
4784 if(!needsTransform
) {
4785 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
4786 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
4787 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
4789 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4790 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4791 ft_face
->glyph
->metrics
.height
) & -64;
4792 lpgm
->gmCellIncX
= adv
;
4793 lpgm
->gmCellIncY
= 0;
4800 for(xc
= 0; xc
< 2; xc
++) {
4801 for(yc
= 0; yc
< 2; yc
++) {
4802 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4803 xc
* ft_face
->glyph
->metrics
.width
);
4804 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4805 yc
* ft_face
->glyph
->metrics
.height
;
4806 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4807 pFT_Vector_Transform(&vec
, &transMat
);
4808 if(xc
== 0 && yc
== 0) {
4809 left
= right
= vec
.x
;
4810 top
= bottom
= vec
.y
;
4812 if(vec
.x
< left
) left
= vec
.x
;
4813 else if(vec
.x
> right
) right
= vec
.x
;
4814 if(vec
.y
< bottom
) bottom
= vec
.y
;
4815 else if(vec
.y
> top
) top
= vec
.y
;
4820 right
= (right
+ 63) & -64;
4821 bottom
= bottom
& -64;
4822 top
= (top
+ 63) & -64;
4824 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4825 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4827 pFT_Vector_Transform(&vec
, &transMat
);
4828 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4829 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4831 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4833 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
4834 adv
= (vec
.x
+63) >> 6;
4838 bbx
= (right
- left
) >> 6;
4839 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4840 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4841 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4842 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4844 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4845 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4846 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4848 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
4849 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
4851 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4852 FONT_GM(font
,original_index
)->adv
= adv
;
4853 FONT_GM(font
,original_index
)->lsb
= lsb
;
4854 FONT_GM(font
,original_index
)->bbx
= bbx
;
4855 FONT_GM(font
,original_index
)->init
= TRUE
;
4858 if(format
== GGO_METRICS
)
4860 LeaveCriticalSection( &freetype_cs
);
4861 return 1; /* FIXME */
4864 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
4865 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4866 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4867 format
== GGO_GRAY8_BITMAP
))
4869 TRACE("loaded a bitmap\n");
4870 LeaveCriticalSection( &freetype_cs
);
4876 width
= lpgm
->gmBlackBoxX
;
4877 height
= lpgm
->gmBlackBoxY
;
4878 pitch
= ((width
+ 31) >> 5) << 2;
4879 needed
= pitch
* height
;
4881 if(!buf
|| !buflen
) break;
4883 switch(ft_face
->glyph
->format
) {
4884 case ft_glyph_format_bitmap
:
4886 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4887 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4888 INT h
= ft_face
->glyph
->bitmap
.rows
;
4890 memcpy(dst
, src
, w
);
4891 src
+= ft_face
->glyph
->bitmap
.pitch
;
4897 case ft_glyph_format_outline
:
4898 ft_bitmap
.width
= width
;
4899 ft_bitmap
.rows
= height
;
4900 ft_bitmap
.pitch
= pitch
;
4901 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4902 ft_bitmap
.buffer
= buf
;
4905 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4907 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4909 /* Note: FreeType will only set 'black' bits for us. */
4910 memset(buf
, 0, needed
);
4911 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4915 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4916 LeaveCriticalSection( &freetype_cs
);
4921 case GGO_GRAY2_BITMAP
:
4922 case GGO_GRAY4_BITMAP
:
4923 case GGO_GRAY8_BITMAP
:
4924 case WINE_GGO_GRAY16_BITMAP
:
4926 unsigned int mult
, row
, col
;
4929 width
= lpgm
->gmBlackBoxX
;
4930 height
= lpgm
->gmBlackBoxY
;
4931 pitch
= (width
+ 3) / 4 * 4;
4932 needed
= pitch
* height
;
4934 if(!buf
|| !buflen
) break;
4936 switch(ft_face
->glyph
->format
) {
4937 case ft_glyph_format_bitmap
:
4939 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4940 INT h
= ft_face
->glyph
->bitmap
.rows
;
4942 memset( buf
, 0, needed
);
4944 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
4945 if (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) dst
[x
] = 0xff;
4946 src
+= ft_face
->glyph
->bitmap
.pitch
;
4949 LeaveCriticalSection( &freetype_cs
);
4952 case ft_glyph_format_outline
:
4954 ft_bitmap
.width
= width
;
4955 ft_bitmap
.rows
= height
;
4956 ft_bitmap
.pitch
= pitch
;
4957 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4958 ft_bitmap
.buffer
= buf
;
4961 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4963 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4965 memset(ft_bitmap
.buffer
, 0, buflen
);
4967 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4969 if(format
== GGO_GRAY2_BITMAP
)
4971 else if(format
== GGO_GRAY4_BITMAP
)
4973 else if(format
== GGO_GRAY8_BITMAP
)
4975 else /* format == WINE_GGO_GRAY16_BITMAP */
4977 LeaveCriticalSection( &freetype_cs
);
4983 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4984 LeaveCriticalSection( &freetype_cs
);
4989 for(row
= 0; row
< height
; row
++) {
4991 for(col
= 0; col
< width
; col
++, ptr
++) {
4992 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4999 case WINE_GGO_HRGB_BITMAP
:
5000 case WINE_GGO_HBGR_BITMAP
:
5001 case WINE_GGO_VRGB_BITMAP
:
5002 case WINE_GGO_VBGR_BITMAP
:
5003 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5005 switch (ft_face
->glyph
->format
)
5007 case FT_GLYPH_FORMAT_BITMAP
:
5012 width
= lpgm
->gmBlackBoxX
;
5013 height
= lpgm
->gmBlackBoxY
;
5015 needed
= pitch
* height
;
5017 if (!buf
|| !buflen
) break;
5019 memset(buf
, 0, buflen
);
5021 src
= ft_face
->glyph
->bitmap
.buffer
;
5022 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5024 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5027 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5029 if ( src
[x
/ 8] & (1 << ( (7 - (x
% 8)))) )
5030 ((unsigned int *)dst
)[x
] = ~0u;
5039 case FT_GLYPH_FORMAT_OUTLINE
:
5043 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5044 INT x_shift
, y_shift
;
5046 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5047 FT_Render_Mode render_mode
=
5048 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5049 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5051 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5053 if ( render_mode
== FT_RENDER_MODE_LCD
)
5055 lpgm
->gmBlackBoxX
+= 2;
5056 lpgm
->gmptGlyphOrigin
.x
-= 1;
5060 lpgm
->gmBlackBoxY
+= 2;
5061 lpgm
->gmptGlyphOrigin
.y
+= 1;
5065 width
= lpgm
->gmBlackBoxX
;
5066 height
= lpgm
->gmBlackBoxY
;
5068 needed
= pitch
* height
;
5070 if (!buf
|| !buflen
) break;
5072 memset(buf
, 0, buflen
);
5074 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5076 if ( needsTransform
)
5077 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5079 if ( pFT_Library_SetLcdFilter
)
5080 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5081 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5083 src
= ft_face
->glyph
->bitmap
.buffer
;
5084 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5085 src_width
= ft_face
->glyph
->bitmap
.width
;
5086 src_height
= ft_face
->glyph
->bitmap
.rows
;
5088 if ( render_mode
== FT_RENDER_MODE_LCD
)
5096 rgb_interval
= src_pitch
;
5101 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5102 if ( x_shift
< 0 ) x_shift
= 0;
5103 if ( x_shift
+ (src_width
/ hmul
) > width
)
5104 x_shift
= width
- (src_width
/ hmul
);
5106 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5107 if ( y_shift
< 0 ) y_shift
= 0;
5108 if ( y_shift
+ (src_height
/ vmul
) > height
)
5109 y_shift
= height
- (src_height
/ vmul
);
5111 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5112 while ( src_height
)
5114 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5118 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5119 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5120 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5121 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5125 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5126 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5127 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5128 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5131 src
+= src_pitch
* vmul
;
5140 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5141 LeaveCriticalSection ( &freetype_cs
);
5148 LeaveCriticalSection( &freetype_cs
);
5154 int contour
, point
= 0, first_pt
;
5155 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5156 TTPOLYGONHEADER
*pph
;
5158 DWORD pph_start
, cpfx
, type
;
5160 if(buflen
== 0) buf
= NULL
;
5162 if (needsTransform
&& buf
) {
5163 pFT_Outline_Transform(outline
, &transMat
);
5166 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5168 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5171 pph
->dwType
= TT_POLYGON_TYPE
;
5172 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5174 needed
+= sizeof(*pph
);
5176 while(point
<= outline
->contours
[contour
]) {
5177 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5178 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5179 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5183 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5186 } while(point
<= outline
->contours
[contour
] &&
5187 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5188 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5189 /* At the end of a contour Windows adds the start point, but
5191 if(point
> outline
->contours
[contour
] &&
5192 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5194 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5196 } else if(point
<= outline
->contours
[contour
] &&
5197 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5198 /* add closing pt for bezier */
5200 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5208 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5211 pph
->cb
= needed
- pph_start
;
5217 /* Convert the quadratic Beziers to cubic Beziers.
5218 The parametric eqn for a cubic Bezier is, from PLRM:
5219 r(t) = at^3 + bt^2 + ct + r0
5220 with the control points:
5225 A quadratic Beizer has the form:
5226 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5228 So equating powers of t leads to:
5229 r1 = 2/3 p1 + 1/3 p0
5230 r2 = 2/3 p1 + 1/3 p2
5231 and of course r0 = p0, r3 = p2
5234 int contour
, point
= 0, first_pt
;
5235 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5236 TTPOLYGONHEADER
*pph
;
5238 DWORD pph_start
, cpfx
, type
;
5239 FT_Vector cubic_control
[4];
5240 if(buflen
== 0) buf
= NULL
;
5242 if (needsTransform
&& buf
) {
5243 pFT_Outline_Transform(outline
, &transMat
);
5246 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5248 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5251 pph
->dwType
= TT_POLYGON_TYPE
;
5252 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5254 needed
+= sizeof(*pph
);
5256 while(point
<= outline
->contours
[contour
]) {
5257 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5258 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5259 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5262 if(type
== TT_PRIM_LINE
) {
5264 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5268 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5271 /* FIXME: Possible optimization in endpoint calculation
5272 if there are two consecutive curves */
5273 cubic_control
[0] = outline
->points
[point
-1];
5274 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5275 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5276 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5277 cubic_control
[0].x
>>= 1;
5278 cubic_control
[0].y
>>= 1;
5280 if(point
+1 > outline
->contours
[contour
])
5281 cubic_control
[3] = outline
->points
[first_pt
];
5283 cubic_control
[3] = outline
->points
[point
+1];
5284 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5285 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5286 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5287 cubic_control
[3].x
>>= 1;
5288 cubic_control
[3].y
>>= 1;
5291 /* r1 = 1/3 p0 + 2/3 p1
5292 r2 = 1/3 p2 + 2/3 p1 */
5293 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5294 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5295 cubic_control
[2] = cubic_control
[1];
5296 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5297 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5298 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5299 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5301 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5302 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5303 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5308 } while(point
<= outline
->contours
[contour
] &&
5309 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5310 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5311 /* At the end of a contour Windows adds the start point,
5312 but only for Beziers and we've already done that.
5314 if(point
<= outline
->contours
[contour
] &&
5315 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5316 /* This is the closing pt of a bezier, but we've already
5317 added it, so just inc point and carry on */
5324 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5327 pph
->cb
= needed
- pph_start
;
5333 FIXME("Unsupported format %d\n", format
);
5334 LeaveCriticalSection( &freetype_cs
);
5337 LeaveCriticalSection( &freetype_cs
);
5341 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5343 FT_Face ft_face
= font
->ft_face
;
5344 #ifdef HAVE_FREETYPE_FTWINFNT_H
5345 FT_WinFNT_HeaderRec winfnt_header
;
5347 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5348 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5349 font
->potm
->otmSize
= size
;
5351 #define TM font->potm->otmTextMetrics
5352 #ifdef HAVE_FREETYPE_FTWINFNT_H
5353 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5355 TM
.tmHeight
= winfnt_header
.pixel_height
;
5356 TM
.tmAscent
= winfnt_header
.ascent
;
5357 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5358 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5359 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5360 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5361 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5362 TM
.tmWeight
= winfnt_header
.weight
;
5364 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5365 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5366 TM
.tmFirstChar
= winfnt_header
.first_char
;
5367 TM
.tmLastChar
= winfnt_header
.last_char
;
5368 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5369 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5370 TM
.tmItalic
= winfnt_header
.italic
;
5371 TM
.tmUnderlined
= font
->underline
;
5372 TM
.tmStruckOut
= font
->strikeout
;
5373 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5374 TM
.tmCharSet
= winfnt_header
.charset
;
5379 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5380 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5381 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5382 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5383 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5384 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5385 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5386 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5388 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5389 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5391 TM
.tmLastChar
= 255;
5392 TM
.tmDefaultChar
= 32;
5393 TM
.tmBreakChar
= 32;
5394 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5395 TM
.tmUnderlined
= font
->underline
;
5396 TM
.tmStruckOut
= font
->strikeout
;
5397 /* NB inverted meaning of TMPF_FIXED_PITCH */
5398 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5399 TM
.tmCharSet
= font
->charset
;
5407 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5409 double scale_x
, scale_y
;
5413 scale_x
= (double)font
->aveWidth
;
5414 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5417 scale_x
= font
->scale_y
;
5419 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5420 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5422 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5423 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5425 SCALE_Y(ptm
->tmHeight
);
5426 SCALE_Y(ptm
->tmAscent
);
5427 SCALE_Y(ptm
->tmDescent
);
5428 SCALE_Y(ptm
->tmInternalLeading
);
5429 SCALE_Y(ptm
->tmExternalLeading
);
5430 SCALE_Y(ptm
->tmOverhang
);
5432 SCALE_X(ptm
->tmAveCharWidth
);
5433 SCALE_X(ptm
->tmMaxCharWidth
);
5439 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5441 double scale_x
, scale_y
;
5445 scale_x
= (double)font
->aveWidth
;
5446 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5449 scale_x
= font
->scale_y
;
5451 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5452 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5454 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5456 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5457 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5459 SCALE_Y(potm
->otmAscent
);
5460 SCALE_Y(potm
->otmDescent
);
5461 SCALE_Y(potm
->otmLineGap
);
5462 SCALE_Y(potm
->otmsCapEmHeight
);
5463 SCALE_Y(potm
->otmsXHeight
);
5464 SCALE_Y(potm
->otmrcFontBox
.top
);
5465 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5466 SCALE_X(potm
->otmrcFontBox
.left
);
5467 SCALE_X(potm
->otmrcFontBox
.right
);
5468 SCALE_Y(potm
->otmMacAscent
);
5469 SCALE_Y(potm
->otmMacDescent
);
5470 SCALE_Y(potm
->otmMacLineGap
);
5471 SCALE_X(potm
->otmptSubscriptSize
.x
);
5472 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5473 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5474 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5475 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5476 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5477 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5478 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5479 SCALE_Y(potm
->otmsStrikeoutSize
);
5480 SCALE_Y(potm
->otmsStrikeoutPosition
);
5481 SCALE_Y(potm
->otmsUnderscoreSize
);
5482 SCALE_Y(potm
->otmsUnderscorePosition
);
5488 /*************************************************************
5489 * WineEngGetTextMetrics
5492 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5495 EnterCriticalSection( &freetype_cs
);
5497 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
5498 if(!get_bitmap_text_metrics(font
))
5500 LeaveCriticalSection( &freetype_cs
);
5504 /* Make sure that the font has sane width/height ratio */
5507 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
5509 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
5515 *ptm
= font
->potm
->otmTextMetrics
;
5516 scale_font_metrics(font
, ptm
);
5517 LeaveCriticalSection( &freetype_cs
);
5521 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
5525 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
5527 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
5533 /*************************************************************
5534 * WineEngGetOutlineTextMetrics
5537 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5538 OUTLINETEXTMETRICW
*potm
)
5540 FT_Face ft_face
= font
->ft_face
;
5541 UINT needed
, lenfam
, lensty
, ret
;
5543 TT_HoriHeader
*pHori
;
5544 TT_Postscript
*pPost
;
5545 FT_Fixed x_scale
, y_scale
;
5546 WCHAR
*family_nameW
, *style_nameW
;
5547 static const WCHAR spaceW
[] = {' ', '\0'};
5549 INT ascent
, descent
;
5551 TRACE("font=%p\n", font
);
5553 if(!FT_IS_SCALABLE(ft_face
))
5557 EnterCriticalSection( &freetype_cs
);
5560 if(cbSize
>= font
->potm
->otmSize
)
5562 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5563 scale_outline_font_metrics(font
, potm
);
5565 LeaveCriticalSection( &freetype_cs
);
5566 return font
->potm
->otmSize
;
5570 needed
= sizeof(*potm
);
5572 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
5573 family_nameW
= strdupW(font
->name
);
5575 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
5577 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
5578 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
5579 style_nameW
, lensty
/sizeof(WCHAR
));
5581 /* These names should be read from the TT name table */
5583 /* length of otmpFamilyName */
5586 /* length of otmpFaceName */
5587 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
5588 needed
+= lenfam
; /* just the family name */
5590 needed
+= lenfam
+ lensty
; /* family + " " + style */
5593 /* length of otmpStyleName */
5596 /* length of otmpFullName */
5597 needed
+= lenfam
+ lensty
;
5600 x_scale
= ft_face
->size
->metrics
.x_scale
;
5601 y_scale
= ft_face
->size
->metrics
.y_scale
;
5603 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
5605 FIXME("Can't find OS/2 table - not TT font?\n");
5610 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
5612 FIXME("Can't find HHEA table - not TT font?\n");
5617 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
5619 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",
5620 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
5621 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
5622 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
5623 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
5624 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
5626 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
5627 font
->potm
->otmSize
= needed
;
5629 #define TM font->potm->otmTextMetrics
5631 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
5632 ascent
= pHori
->Ascender
;
5633 descent
= -pHori
->Descender
;
5635 ascent
= pOS2
->usWinAscent
;
5636 descent
= pOS2
->usWinDescent
;
5640 TM
.tmAscent
= font
->yMax
;
5641 TM
.tmDescent
= -font
->yMin
;
5642 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
5644 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
5645 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
5646 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
5647 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
5650 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5653 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5655 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
5656 ((ascent
+ descent
) -
5657 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
5659 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
5660 if (TM
.tmAveCharWidth
== 0) {
5661 TM
.tmAveCharWidth
= 1;
5663 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5664 TM
.tmWeight
= FW_REGULAR
;
5665 if (font
->fake_bold
)
5666 TM
.tmWeight
= FW_BOLD
;
5669 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
5671 if (pOS2
->usWeightClass
> FW_MEDIUM
)
5672 TM
.tmWeight
= pOS2
->usWeightClass
;
5674 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
5675 TM
.tmWeight
= pOS2
->usWeightClass
;
5678 TM
.tmDigitizedAspectX
= 300;
5679 TM
.tmDigitizedAspectY
= 300;
5680 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5681 * symbol range to 0 - f0ff
5684 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
5689 case 1257: /* Baltic */
5690 TM
.tmLastChar
= 0xf8fd;
5693 TM
.tmLastChar
= 0xf0ff;
5695 TM
.tmBreakChar
= 0x20;
5696 TM
.tmDefaultChar
= 0x1f;
5700 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
5701 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
5703 if(pOS2
->usFirstCharIndex
<= 1)
5704 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
5705 else if (pOS2
->usFirstCharIndex
> 0xff)
5706 TM
.tmBreakChar
= 0x20;
5708 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
5709 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
5711 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
5712 TM
.tmUnderlined
= font
->underline
;
5713 TM
.tmStruckOut
= font
->strikeout
;
5715 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5716 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
5717 (pOS2
->version
== 0xFFFFU
||
5718 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
5719 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
5721 TM
.tmPitchAndFamily
= 0;
5723 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
5725 case PAN_FAMILY_SCRIPT
:
5726 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
5729 case PAN_FAMILY_DECORATIVE
:
5730 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
5735 case PAN_FAMILY_TEXT_DISPLAY
:
5736 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
5737 /* which is clearly not what the panose spec says. */
5739 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
5740 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
5741 TM
.tmPitchAndFamily
= FF_MODERN
;
5744 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
5749 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
5752 case PAN_SERIF_COVE
:
5753 case PAN_SERIF_OBTUSE_COVE
:
5754 case PAN_SERIF_SQUARE_COVE
:
5755 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
5756 case PAN_SERIF_SQUARE
:
5757 case PAN_SERIF_THIN
:
5758 case PAN_SERIF_BONE
:
5759 case PAN_SERIF_EXAGGERATED
:
5760 case PAN_SERIF_TRIANGLE
:
5761 TM
.tmPitchAndFamily
|= FF_ROMAN
;
5764 case PAN_SERIF_NORMAL_SANS
:
5765 case PAN_SERIF_OBTUSE_SANS
:
5766 case PAN_SERIF_PERP_SANS
:
5767 case PAN_SERIF_FLARED
:
5768 case PAN_SERIF_ROUNDED
:
5769 TM
.tmPitchAndFamily
|= FF_SWISS
;
5776 if(FT_IS_SCALABLE(ft_face
))
5777 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
5779 if(FT_IS_SFNT(ft_face
))
5781 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
5782 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
5784 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
5787 TM
.tmCharSet
= font
->charset
;
5789 font
->potm
->otmFiller
= 0;
5790 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
5791 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
5792 font
->potm
->otmfsType
= pOS2
->fsType
;
5793 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
5794 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
5795 font
->potm
->otmItalicAngle
= 0; /* POST table */
5796 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
5797 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
5798 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
5799 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
5800 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
5801 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5802 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5803 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5804 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5805 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5806 font
->potm
->otmMacAscent
= TM
.tmAscent
;
5807 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
5808 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
5809 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5810 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5811 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5812 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5813 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5814 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5815 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5816 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5817 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5818 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5819 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5821 font
->potm
->otmsUnderscoreSize
= 0;
5822 font
->potm
->otmsUnderscorePosition
= 0;
5824 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5825 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5829 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5830 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5831 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5832 strcpyW((WCHAR
*)cp
, family_nameW
);
5834 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5835 strcpyW((WCHAR
*)cp
, style_nameW
);
5837 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5838 strcpyW((WCHAR
*)cp
, family_nameW
);
5839 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
5840 strcatW((WCHAR
*)cp
, spaceW
);
5841 strcatW((WCHAR
*)cp
, style_nameW
);
5842 cp
+= lenfam
+ lensty
;
5845 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5846 strcpyW((WCHAR
*)cp
, family_nameW
);
5847 strcatW((WCHAR
*)cp
, spaceW
);
5848 strcatW((WCHAR
*)cp
, style_nameW
);
5851 if(potm
&& needed
<= cbSize
)
5853 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5854 scale_outline_font_metrics(font
, potm
);
5858 HeapFree(GetProcessHeap(), 0, style_nameW
);
5859 HeapFree(GetProcessHeap(), 0, family_nameW
);
5861 LeaveCriticalSection( &freetype_cs
);
5865 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5867 HFONTLIST
*hfontlist
;
5868 child
->font
= alloc_font();
5869 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5870 if(!child
->font
->ft_face
)
5872 free_font(child
->font
);
5877 child
->font
->font_desc
= font
->font_desc
;
5878 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5879 child
->font
->orientation
= font
->orientation
;
5880 child
->font
->scale_y
= font
->scale_y
;
5881 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5882 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5883 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
5884 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5885 child
->font
->base_font
= font
;
5886 list_add_head(&child_font_list
, &child
->font
->entry
);
5887 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5891 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5894 CHILD_FONT
*child_font
;
5897 font
= font
->base_font
;
5899 *linked_font
= font
;
5901 if((*glyph
= get_glyph_index(font
, c
)))
5904 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5906 if(!child_font
->font
)
5907 if(!load_child_font(font
, child_font
))
5910 if(!child_font
->font
->ft_face
)
5912 g
= get_glyph_index(child_font
->font
, c
);
5916 *linked_font
= child_font
->font
;
5923 /*************************************************************
5924 * WineEngGetCharWidth
5927 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5930 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5933 FT_UInt glyph_index
;
5934 GdiFont
*linked_font
;
5936 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5939 EnterCriticalSection( &freetype_cs
);
5940 for(c
= firstChar
; c
<= lastChar
; c
++) {
5941 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5942 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5943 &gm
, 0, NULL
, &identity
);
5944 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5946 LeaveCriticalSection( &freetype_cs
);
5950 /*************************************************************
5951 * WineEngGetCharABCWidths
5954 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5957 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5960 FT_UInt glyph_index
;
5961 GdiFont
*linked_font
;
5963 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5965 if(!FT_IS_SCALABLE(font
->ft_face
))
5969 EnterCriticalSection( &freetype_cs
);
5971 for(c
= firstChar
; c
<= lastChar
; c
++) {
5972 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5973 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5974 &gm
, 0, NULL
, &identity
);
5975 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
5976 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
5977 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
5978 FONT_GM(linked_font
,glyph_index
)->bbx
;
5980 LeaveCriticalSection( &freetype_cs
);
5984 /*************************************************************
5985 * WineEngGetCharABCWidthsFloat
5988 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
5990 static const MAT2 identity
= {{0,1}, {0,0}, {0,0}, {0,1}};
5993 FT_UInt glyph_index
;
5994 GdiFont
*linked_font
;
5996 TRACE("%p, %d, %d, %p\n", font
, first
, last
, buffer
);
5999 EnterCriticalSection( &freetype_cs
);
6001 for (c
= first
; c
<= last
; c
++)
6003 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
6004 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6005 &gm
, 0, NULL
, &identity
);
6006 buffer
[c
- first
].abcfA
= FONT_GM(linked_font
, glyph_index
)->lsb
;
6007 buffer
[c
- first
].abcfB
= FONT_GM(linked_font
, glyph_index
)->bbx
;
6008 buffer
[c
- first
].abcfC
= FONT_GM(linked_font
, glyph_index
)->adv
-
6009 FONT_GM(linked_font
, glyph_index
)->lsb
-
6010 FONT_GM(linked_font
, glyph_index
)->bbx
;
6012 LeaveCriticalSection( &freetype_cs
);
6016 /*************************************************************
6017 * WineEngGetCharABCWidthsI
6020 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6023 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6026 FT_UInt glyph_index
;
6027 GdiFont
*linked_font
;
6029 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
6033 EnterCriticalSection( &freetype_cs
);
6035 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
6037 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6038 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6039 &gm
, 0, NULL
, &identity
);
6040 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6041 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6042 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6043 - FONT_GM(linked_font
,c
)->bbx
;
6046 for(c
= 0; c
< count
; c
++) {
6047 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6048 &gm
, 0, NULL
, &identity
);
6049 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6050 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6051 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6052 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6055 LeaveCriticalSection( &freetype_cs
);
6059 /*************************************************************
6060 * WineEngGetTextExtentExPoint
6063 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6064 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6066 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6071 FT_UInt glyph_index
;
6072 GdiFont
*linked_font
;
6074 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
6078 EnterCriticalSection( &freetype_cs
);
6081 WineEngGetTextMetrics(font
, &tm
);
6082 size
->cy
= tm
.tmHeight
;
6084 for(idx
= 0; idx
< count
; idx
++) {
6085 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
6086 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6087 &gm
, 0, NULL
, &identity
);
6088 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6090 if (! pnfit
|| ext
<= max_ext
) {
6100 LeaveCriticalSection( &freetype_cs
);
6101 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6105 /*************************************************************
6106 * WineEngGetTextExtentExPointI
6109 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6110 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6112 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6118 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
6121 EnterCriticalSection( &freetype_cs
);
6124 WineEngGetTextMetrics(font
, &tm
);
6125 size
->cy
= tm
.tmHeight
;
6127 for(idx
= 0; idx
< count
; idx
++) {
6128 WineEngGetGlyphOutline(font
, indices
[idx
],
6129 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
6131 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
6133 if (! pnfit
|| ext
<= max_ext
) {
6143 LeaveCriticalSection( &freetype_cs
);
6144 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6148 /*************************************************************
6149 * WineEngGetFontData
6152 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6155 FT_Face ft_face
= font
->ft_face
;
6159 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6160 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6161 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6163 if(!FT_IS_SFNT(ft_face
))
6171 if(table
) { /* MS tags differ in endianness from FT ones */
6172 table
= table
>> 24 | table
<< 24 |
6173 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
6176 /* make sure value of len is the value freetype says it needs */
6179 FT_ULong needed
= 0;
6180 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
6181 if( !err
&& needed
< len
) len
= needed
;
6183 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
6186 TRACE("Can't find table %c%c%c%c\n",
6187 /* bytes were reversed */
6188 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
6189 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
6195 /*************************************************************
6196 * WineEngGetTextFace
6199 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6201 INT n
= strlenW(font
->name
) + 1;
6203 lstrcpynW(str
, font
->name
, count
);
6204 return min(count
, n
);
6209 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6211 if (fs
) *fs
= font
->fs
;
6212 return font
->charset
;
6215 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6217 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6218 struct list
*first_hfont
;
6222 EnterCriticalSection( &freetype_cs
);
6223 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6224 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6225 if(font
== linked_font
)
6226 *new_hfont
= dc
->hFont
;
6229 first_hfont
= list_head(&linked_font
->hfontlist
);
6230 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6232 LeaveCriticalSection( &freetype_cs
);
6236 /* Retrieve a list of supported Unicode ranges for a given font.
6237 * Can be called with NULL gs to calculate the buffer size. Returns
6238 * the number of ranges found.
6240 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6242 DWORD num_ranges
= 0;
6244 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6247 FT_ULong char_code
, char_code_prev
;
6250 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6252 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6253 face
->num_glyphs
, glyph_code
, char_code
);
6255 if (!glyph_code
) return 0;
6259 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6260 gs
->ranges
[0].cGlyphs
= 0;
6261 gs
->cGlyphsSupported
= 0;
6267 if (char_code
< char_code_prev
)
6269 ERR("expected increasing char code from FT_Get_Next_Char\n");
6272 if (char_code
- char_code_prev
> 1)
6277 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6278 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6279 gs
->cGlyphsSupported
++;
6284 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6285 gs
->cGlyphsSupported
++;
6287 char_code_prev
= char_code
;
6288 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6292 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6297 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6300 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
6302 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6305 glyphset
->cbThis
= size
;
6306 glyphset
->cRanges
= num_ranges
;
6307 glyphset
->flAccel
= 0;
6312 /*************************************************************
6315 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6319 EnterCriticalSection( &freetype_cs
);
6320 ret
= !list_empty(&font
->child_fonts
);
6321 LeaveCriticalSection( &freetype_cs
);
6325 static BOOL
is_hinting_enabled(void)
6327 /* Use the >= 2.2.0 function if available */
6328 if(pFT_Get_TrueType_Engine_Type
)
6330 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6331 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6333 #ifdef FT_DRIVER_HAS_HINTER
6338 /* otherwise if we've been compiled with < 2.2.0 headers
6339 use the internal macro */
6340 mod
= pFT_Get_Module(library
, "truetype");
6341 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6349 static BOOL
is_subpixel_rendering_enabled( void )
6351 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6352 return pFT_Library_SetLcdFilter
&&
6353 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6359 /*************************************************************************
6360 * GetRasterizerCaps (GDI32.@)
6362 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6364 static int hinting
= -1;
6365 static int subpixel
= -1;
6369 hinting
= is_hinting_enabled();
6370 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6373 if ( subpixel
== -1 )
6375 subpixel
= is_subpixel_rendering_enabled();
6376 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6379 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6380 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6382 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6383 lprs
->nLanguageID
= 0;
6387 /*************************************************************
6388 * WineEngRealizationInfo
6390 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6392 FIXME("(%p, %p): stub!\n", font
, info
);
6395 if(FT_IS_SCALABLE(font
->ft_face
))
6398 info
->cache_num
= font
->cache_num
;
6399 info
->unknown2
= -1;
6403 /*************************************************************************
6404 * Kerning support for TrueType fonts
6406 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6408 struct TT_kern_table
6414 struct TT_kern_subtable
6423 USHORT horizontal
: 1;
6425 USHORT cross_stream
: 1;
6426 USHORT override
: 1;
6427 USHORT reserved1
: 4;
6433 struct TT_format0_kern_subtable
6437 USHORT entrySelector
;
6448 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
6449 const struct TT_format0_kern_subtable
*tt_f0_ks
,
6450 const USHORT
*glyph_to_char
,
6451 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
6454 const struct TT_kern_pair
*tt_kern_pair
;
6456 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
6458 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
6460 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6461 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
6462 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
6464 if (!kern_pair
|| !cPairs
)
6467 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
6469 nPairs
= min(nPairs
, cPairs
);
6471 for (i
= 0; i
< nPairs
; i
++)
6473 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
6474 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
6475 /* this algorithm appears to better match what Windows does */
6476 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
6477 if (kern_pair
->iKernAmount
< 0)
6479 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
6480 kern_pair
->iKernAmount
-= font
->ppem
;
6482 else if (kern_pair
->iKernAmount
> 0)
6484 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
6485 kern_pair
->iKernAmount
+= font
->ppem
;
6487 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
6489 TRACE("left %u right %u value %d\n",
6490 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
6494 TRACE("copied %u entries\n", nPairs
);
6498 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6502 const struct TT_kern_table
*tt_kern_table
;
6503 const struct TT_kern_subtable
*tt_kern_subtable
;
6505 USHORT
*glyph_to_char
;
6508 EnterCriticalSection( &freetype_cs
);
6509 if (font
->total_kern_pairs
!= (DWORD
)-1)
6511 if (cPairs
&& kern_pair
)
6513 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6514 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6515 LeaveCriticalSection( &freetype_cs
);
6518 LeaveCriticalSection( &freetype_cs
);
6519 return font
->total_kern_pairs
;
6522 font
->total_kern_pairs
= 0;
6524 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
6526 if (length
== GDI_ERROR
)
6528 TRACE("no kerning data in the font\n");
6529 LeaveCriticalSection( &freetype_cs
);
6533 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
6536 WARN("Out of memory\n");
6537 LeaveCriticalSection( &freetype_cs
);
6541 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
6543 /* build a glyph index to char code map */
6544 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
6547 WARN("Out of memory allocating a glyph index to char code map\n");
6548 HeapFree(GetProcessHeap(), 0, buf
);
6549 LeaveCriticalSection( &freetype_cs
);
6553 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6559 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
6561 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6562 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
6566 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6568 /* FIXME: This doesn't match what Windows does: it does some fancy
6569 * things with duplicate glyph index to char code mappings, while
6570 * we just avoid overriding existing entries.
6572 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
6573 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
6575 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
6582 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
6583 for (n
= 0; n
<= 65535; n
++)
6584 glyph_to_char
[n
] = (USHORT
)n
;
6587 tt_kern_table
= buf
;
6588 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
6589 TRACE("version %u, nTables %u\n",
6590 GET_BE_WORD(tt_kern_table
->version
), nTables
);
6592 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
6594 for (i
= 0; i
< nTables
; i
++)
6596 struct TT_kern_subtable tt_kern_subtable_copy
;
6598 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
6599 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
6600 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
6602 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6603 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
6604 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
6606 /* According to the TrueType specification this is the only format
6607 * that will be properly interpreted by Windows and OS/2
6609 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
6611 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
6613 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6614 glyph_to_char
, NULL
, 0);
6615 font
->total_kern_pairs
+= new_chunk
;
6617 if (!font
->kern_pairs
)
6618 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
6619 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6621 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
6622 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6624 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6625 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
6628 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
6630 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
6633 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
6634 HeapFree(GetProcessHeap(), 0, buf
);
6636 if (cPairs
&& kern_pair
)
6638 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6639 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6640 LeaveCriticalSection( &freetype_cs
);
6643 LeaveCriticalSection( &freetype_cs
);
6644 return font
->total_kern_pairs
;
6647 #else /* HAVE_FREETYPE */
6649 /*************************************************************************/
6651 BOOL
WineEngInit(void)
6655 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
6659 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
6664 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6669 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
6670 LPWORD pgi
, DWORD flags
)
6675 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
6676 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
6679 ERR("called but we don't have FreeType\n");
6683 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6685 ERR("called but we don't have FreeType\n");
6689 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
6690 OUTLINETEXTMETRICW
*potm
)
6692 ERR("called but we don't have FreeType\n");
6696 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6699 ERR("called but we don't have FreeType\n");
6703 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6706 ERR("called but we don't have FreeType\n");
6710 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
6712 ERR("called but we don't have FreeType\n");
6716 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6719 ERR("called but we don't have FreeType\n");
6723 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6724 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6726 ERR("called but we don't have FreeType\n");
6730 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6731 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6733 ERR("called but we don't have FreeType\n");
6737 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6740 ERR("called but we don't have FreeType\n");
6744 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6746 ERR("called but we don't have FreeType\n");
6750 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6752 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
6756 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6758 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
6762 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
6764 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
6768 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6770 FIXME("(%p, %p, %u): stub\n", font
, fs
, flags
);
6771 return DEFAULT_CHARSET
;
6774 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6779 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6781 FIXME("(%p, %p): stub\n", font
, glyphset
);
6785 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6790 /*************************************************************************
6791 * GetRasterizerCaps (GDI32.@)
6793 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6795 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6797 lprs
->nLanguageID
= 0;
6801 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6803 ERR("called but we don't have FreeType\n");
6807 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6809 ERR("called but we don't have FreeType\n");
6813 #endif /* HAVE_FREETYPE */